diff -Nru orthanc-mysql-2.0/debian/changelog orthanc-mysql-3.0/debian/changelog --- orthanc-mysql-2.0/debian/changelog 2020-12-12 12:19:39.000000000 +0000 +++ orthanc-mysql-3.0/debian/changelog 2020-12-17 07:58:15.000000000 +0000 @@ -1,23 +1,9 @@ -orthanc-mysql (2.0-3ubuntu3) hirsute; urgency=medium +orthanc-mysql (3.0-1) unstable; urgency=medium - * No-change rebuild for boost soname change. + * New upstream version + * Dynamic linking against "liborthancframework*" - -- Matthias Klose Sat, 12 Dec 2020 13:19:39 +0100 - -orthanc-mysql (2.0-3ubuntu2) hirsute; urgency=medium - - * Rebuild against new libjsoncpp24. - - -- Gianfranco Costamagna Mon, 07 Dec 2020 15:30:38 +0100 - -orthanc-mysql (2.0-3ubuntu1) groovy; urgency=low - - * Merge from Debian unstable. Remaining changes: - - d/p/mysql8_my_bool.patch: Reintroduce my_bool to fix build with MySQL 8. - * Dropped changes, fixed in Debian: - - switch back with the orthanc framework provided by Debian - - -- Gianfranco Costamagna Fri, 31 Jul 2020 14:48:54 +0200 + -- Sebastien Jodogne Thu, 17 Dec 2020 08:58:15 +0100 orthanc-mysql (2.0-3) unstable; urgency=medium @@ -25,13 +11,6 @@ -- Sebastien Jodogne Fri, 05 Jun 2020 10:33:02 +0200 -orthanc-mysql (2.0-2ubuntu3) focal; urgency=medium - - * d/p/mysql8_my_bool.patch: Reintroduce my_bool to fix build with MySQL 8. - (LP: #1863026) - - -- Andreas Hasenack Fri, 21 Feb 2020 13:55:23 -0300 - orthanc-mysql (2.0-2) unstable; urgency=medium * Removed $(DEB_VERSION) from SOVERSION. Closes: #920662 diff -Nru orthanc-mysql-2.0/debian/control orthanc-mysql-3.0/debian/control --- orthanc-mysql-2.0/debian/control 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/control 2020-12-17 07:58:15.000000000 +0000 @@ -5,16 +5,13 @@ Priority: optional Build-Depends: cmake, debhelper (>= 10), - libboost-all-dev, - libcurl4-openssl-dev | libcurl4-dev, libgtest-dev, - libjsoncpp-dev, + liborthancframework-dev, libssl-dev, orthanc-dev, default-libmysqlclient-dev, - unzip, - uuid-dev -Standards-Version: 4.5.0 + unzip +Standards-Version: 4.5.1 Vcs-Browser: https://salsa.debian.org/med-team/orthanc-mysql Vcs-Git: https://salsa.debian.org/med-team/orthanc-mysql.git Homepage: https://www.orthanc-server.com/static.php?page=mysql diff -Nru orthanc-mysql-2.0/debian/copyright orthanc-mysql-3.0/debian/copyright --- orthanc-mysql-2.0/debian/copyright 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/copyright 2020-12-17 07:58:15.000000000 +0000 @@ -1,28 +1,16 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: OrthancMySQL Upstream-Contact: Sebastien Jodogne -Source: https://bitbucket.org/sjodogne/orthanc-databases +Source: https://hg.orthanc-server.com/orthanc-databases/ Files: * -Copyright: 2012-2016 Sebastien Jodogne , University Hospital of Liege (Belgium), and 2017-2019 Osimis S.A. (Belgium) +Copyright: 2012-2016 Sebastien Jodogne , University Hospital of Liege (Belgium), and 2017-2020 Osimis S.A. (Belgium) License: AGPL-3 -Files: Resources/Orthanc/* debian/orthanc-framework/* +Files: Resources/Orthanc/* Copyright: 2012-2016 Sebastien Jodogne , University Hospital of Liege (Belgium), and 2017-2020 Osimis S.A. (Belgium) License: GPL-3 with OpenSSL exception -Files: debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/* -Copyright: 2004-2008 Rene Nyffenegger -License: zlib - -Files: debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/* -Copyright: 1999, 2002 Aladdin Enterprises -License: zlib - -Files: debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/* -Copyright: 1998-2010 Gilles Vollant, and 2009-2010 Mathias Svensson -License: zlib - @@ -71,23 +59,3 @@ On Debian systems, the full text of the GNU General Public License version 3 can be found in the file `/usr/share/common-licenses/GPL-3'. - -License: zlib - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - . - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - . - 1. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product documentation - would be appreciated but is not required. - . - 2. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - . - 3. This notice may not be removed or altered from any source - distribution. diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/AUTHORS orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/AUTHORS --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/AUTHORS 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/AUTHORS 1970-01-01 00:00:00.000000000 +0000 @@ -1,21 +0,0 @@ -Orthanc - A Lightweight, RESTful DICOM Server -============================================= - - -Authors of Orthanc ------------------- - -* Sebastien Jodogne - - Overall design and lead developer. - -* Department of Medical Physics - University Hospital of Liege - 4000 Liege - Belgium - -* Osimis S.A. - Quai Banning 6 - 4000 Liege - Belgium - http://www.osimis.io/ diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/COPYING orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/COPYING --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/COPYING 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/COPYING 1970-01-01 00:00:00.000000000 +0000 @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICacheable.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICacheable.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICacheable.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICacheable.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include - -namespace Orthanc -{ - class ICacheable : public boost::noncopyable - { - public: - virtual ~ICacheable() - { - } - - virtual size_t GetMemoryUsage() const = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICachePageProvider.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICachePageProvider.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICachePageProvider.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/ICachePageProvider.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include "../IDynamicObject.h" - -namespace Orthanc -{ - namespace Deprecated - { - class ICachePageProvider - { - public: - virtual ~ICachePageProvider() - { - } - - virtual IDynamicObject* Provide(const std::string& id) = 0; - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/LeastRecentlyUsedIndex.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/LeastRecentlyUsedIndex.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/LeastRecentlyUsedIndex.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/LeastRecentlyUsedIndex.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,359 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include -#include -#include -#include - -#include "../OrthancException.h" -#include "../Toolbox.h" - -namespace Orthanc -{ - /** - * This class implements the index of a cache with least recently - * used (LRU) recycling policy. All the items of the cache index - * can be associated with a payload. - * Reference: http://stackoverflow.com/a/2504317 - **/ - template - class LeastRecentlyUsedIndex : public boost::noncopyable - { - private: - typedef std::list< std::pair > Queue; - typedef std::map Index; - - Index index_; - Queue queue_; - - /** - * Internal method for debug builds to check whether the internal - * data structures are not corrupted. - **/ - void CheckInvariants() const; - - public: - /** - * Add a new element to the cache index, and make it the most - * recent element. - * \param id The ID of the element. - * \param payload The payload of the element. - **/ - void Add(T id, Payload payload = Payload()); - - void AddOrMakeMostRecent(T id, Payload payload = Payload()); - - /** - * When accessing an element of the cache, this method tags the - * element as the most recently used. - * \param id The most recently accessed item. - **/ - void MakeMostRecent(T id); - - void MakeMostRecent(T id, Payload updatedPayload); - - /** - * Remove an element from the cache index. - * \param id The item to remove. - **/ - Payload Invalidate(T id); - - /** - * Get the oldest element in the cache and remove it. - * \return The oldest item. - **/ - T RemoveOldest(); - - /** - * Get the oldest element in the cache, remove it and return the - * associated payload. - * \param payload Where to store the associated payload. - * \return The oldest item. - **/ - T RemoveOldest(Payload& payload); - - /** - * Check whether an element is contained in the cache. - * \param id The item. - * \return \c true iff the item is indexed by the cache. - **/ - bool Contains(T id) const - { - return index_.find(id) != index_.end(); - } - - bool Contains(T id, Payload& payload) const - { - typename Index::const_iterator it = index_.find(id); - if (it == index_.end()) - { - return false; - } - else - { - payload = it->second->second; - return true; - } - } - - /** - * Return the number of elements in the cache. - * \return The number of elements. - **/ - size_t GetSize() const - { - assert(index_.size() == queue_.size()); - return queue_.size(); - } - - /** - * Check whether the cache index is empty. - * \return \c true iff the cache is empty. - **/ - bool IsEmpty() const - { - return index_.empty(); - } - - const T& GetOldest() const; - - const Payload& GetOldestPayload() const; - - void GetAllKeys(std::vector& keys) const - { - keys.clear(); - keys.reserve(GetSize()); - for (typename Index::const_iterator it = index_.begin(); it != index_.end(); it++) - { - keys.push_back(it->first); - } - } - - }; - - - - - /****************************************************************** - ** Implementation of the template - ******************************************************************/ - - template - void LeastRecentlyUsedIndex::CheckInvariants() const - { -#ifndef NDEBUG - assert(index_.size() == queue_.size()); - - for (typename Index::const_iterator - it = index_.begin(); it != index_.end(); it++) - { - assert(it->second != queue_.end()); - assert(it->second->first == it->first); - } -#endif - } - - - template - void LeastRecentlyUsedIndex::Add(T id, Payload payload) - { - if (Contains(id)) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - queue_.push_front(std::make_pair(id, payload)); - index_[id] = queue_.begin(); - - CheckInvariants(); - } - - - template - void LeastRecentlyUsedIndex::MakeMostRecent(T id) - { - if (!Contains(id)) - { - throw OrthancException(ErrorCode_InexistentItem); - } - - typename Index::iterator it = index_.find(id); - assert(it != index_.end()); - - std::pair item = *(it->second); - - queue_.erase(it->second); - queue_.push_front(item); - index_[id] = queue_.begin(); - - CheckInvariants(); - } - - - template - void LeastRecentlyUsedIndex::AddOrMakeMostRecent(T id, Payload payload) - { - typename Index::iterator it = index_.find(id); - - if (it != index_.end()) - { - // Already existing. Make it most recent. - std::pair item = *(it->second); - item.second = payload; - queue_.erase(it->second); - queue_.push_front(item); - } - else - { - // New item - queue_.push_front(std::make_pair(id, payload)); - } - - index_[id] = queue_.begin(); - - CheckInvariants(); - } - - - template - void LeastRecentlyUsedIndex::MakeMostRecent(T id, Payload updatedPayload) - { - if (!Contains(id)) - { - throw OrthancException(ErrorCode_InexistentItem); - } - - typename Index::iterator it = index_.find(id); - assert(it != index_.end()); - - std::pair item = *(it->second); - item.second = updatedPayload; - - queue_.erase(it->second); - queue_.push_front(item); - index_[id] = queue_.begin(); - - CheckInvariants(); - } - - - template - Payload LeastRecentlyUsedIndex::Invalidate(T id) - { - if (!Contains(id)) - { - throw OrthancException(ErrorCode_InexistentItem); - } - - typename Index::iterator it = index_.find(id); - assert(it != index_.end()); - - Payload payload = it->second->second; - queue_.erase(it->second); - index_.erase(it); - - CheckInvariants(); - return payload; - } - - - template - T LeastRecentlyUsedIndex::RemoveOldest(Payload& payload) - { - if (IsEmpty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - std::pair item = queue_.back(); - T oldest = item.first; - payload = item.second; - - queue_.pop_back(); - assert(index_.find(oldest) != index_.end()); - index_.erase(oldest); - - CheckInvariants(); - - return oldest; - } - - - template - T LeastRecentlyUsedIndex::RemoveOldest() - { - if (IsEmpty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - std::pair item = queue_.back(); - T oldest = item.first; - - queue_.pop_back(); - assert(index_.find(oldest) != index_.end()); - index_.erase(oldest); - - CheckInvariants(); - - return oldest; - } - - - template - const T& LeastRecentlyUsedIndex::GetOldest() const - { - if (IsEmpty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - return queue_.back().first; - } - - - template - const Payload& LeastRecentlyUsedIndex::GetOldestPayload() const - { - if (IsEmpty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - return queue_.back().second; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "MemoryCache.h" - -#include "../Logging.h" - -namespace Orthanc -{ - namespace Deprecated - { - MemoryCache::Page& MemoryCache::Load(const std::string& id) - { - // Reuse the cache entry if it already exists - Page* p = NULL; - if (index_.Contains(id, p)) - { - VLOG(1) << "Reusing a cache page"; - assert(p != NULL); - index_.MakeMostRecent(id); - return *p; - } - - // The id is not in the cache yet. Make some room if the cache - // is full. - if (index_.GetSize() == cacheSize_) - { - VLOG(1) << "Dropping the oldest cache page"; - index_.RemoveOldest(p); - delete p; - } - - // Create a new cache page - std::unique_ptr result(new Page); - result->id_ = id; - result->content_.reset(provider_.Provide(id)); - - // Add the newly create page to the cache - VLOG(1) << "Registering new data in a cache page"; - p = result.release(); - index_.Add(id, p); - return *p; - } - - MemoryCache::MemoryCache(ICachePageProvider& provider, - size_t cacheSize) : - provider_(provider), - cacheSize_(cacheSize) - { - } - - void MemoryCache::Invalidate(const std::string& id) - { - Page* p = NULL; - if (index_.Contains(id, p)) - { - VLOG(1) << "Invalidating a cache page"; - assert(p != NULL); - delete p; - index_.Invalidate(id); - } - } - - MemoryCache::~MemoryCache() - { - while (!index_.IsEmpty()) - { - Page* element = NULL; - index_.RemoveOldest(element); - assert(element != NULL); - delete element; - } - } - - IDynamicObject& MemoryCache::Access(const std::string& id) - { - return *Load(id).content_; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryCache.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Compatibility.h" -#include "ICachePageProvider.h" -#include "LeastRecentlyUsedIndex.h" - -#include - -namespace Orthanc -{ - namespace Deprecated - { - /** - * WARNING: This class is NOT thread-safe. - **/ - class MemoryCache - { - private: - struct Page - { - std::string id_; - std::unique_ptr content_; - }; - - ICachePageProvider& provider_; - size_t cacheSize_; - LeastRecentlyUsedIndex index_; - - Page& Load(const std::string& id); - - public: - MemoryCache(ICachePageProvider& provider, - size_t cacheSize); - - ~MemoryCache(); - - IDynamicObject& Access(const std::string& id); - - void Invalidate(const std::string& id); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,282 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "MemoryObjectCache.h" - -#include "../Compatibility.h" - -namespace Orthanc -{ - class MemoryObjectCache::Item : public boost::noncopyable - { - private: - ICacheable* value_; - boost::posix_time::ptime time_; - - public: - explicit Item(ICacheable* value) : // Takes ownership - value_(value), - time_(boost::posix_time::second_clock::local_time()) - { - if (value == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - } - - ~Item() - { - assert(value_ != NULL); - delete value_; - } - - ICacheable& GetValue() const - { - assert(value_ != NULL); - return *value_; - } - - const boost::posix_time::ptime& GetTime() const - { - return time_; - } - }; - - - void MemoryObjectCache::Recycle(size_t targetSize) - { - // WARNING: "cacheMutex_" must be locked - while (currentSize_ > targetSize) - { - assert(!content_.IsEmpty()); - - Item* item = NULL; - content_.RemoveOldest(item); - - assert(item != NULL); - const size_t size = item->GetValue().GetMemoryUsage(); - delete item; - - assert(currentSize_ >= size); - currentSize_ -= size; - } - - // Post-condition: "currentSize_ <= targetSize" - } - - - MemoryObjectCache::MemoryObjectCache() : - currentSize_(0), - maxSize_(100 * 1024 * 1024) // 100 MB - { - } - - - MemoryObjectCache::~MemoryObjectCache() - { - Recycle(0); - assert(content_.IsEmpty()); - } - - - size_t MemoryObjectCache::GetMaximumSize() - { -#if !defined(__EMSCRIPTEN__) - boost::mutex::scoped_lock lock(cacheMutex_); -#endif - - return maxSize_; - } - - - void MemoryObjectCache::SetMaximumSize(size_t size) - { - if (size == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - -#if !defined(__EMSCRIPTEN__) - // Make sure no accessor is currently open (as its data may be - // removed if recycling is needed) - WriterLock contentLock(contentMutex_); - - // Lock the global structure of the cache - boost::mutex::scoped_lock cacheLock(cacheMutex_); -#endif - - Recycle(size); - maxSize_ = size; - } - - - void MemoryObjectCache::Acquire(const std::string& key, - ICacheable* value) - { - std::unique_ptr item(new Item(value)); - - if (value == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else - { -#if !defined(__EMSCRIPTEN__) - // Make sure no accessor is currently open (as its data may be - // removed if recycling is needed) - WriterLock contentLock(contentMutex_); - - // Lock the global structure of the cache - boost::mutex::scoped_lock cacheLock(cacheMutex_); -#endif - - const size_t size = item->GetValue().GetMemoryUsage(); - - if (size > maxSize_) - { - // This object is too large to be stored in the cache, discard it - } - else if (content_.Contains(key)) - { - // Value already stored, don't overwrite the old value - content_.MakeMostRecent(key); - } - else - { - Recycle(maxSize_ - size); // Post-condition: currentSize_ <= maxSize_ - size - assert(currentSize_ + size <= maxSize_); - - content_.Add(key, item.release()); - currentSize_ += size; - } - } - } - - - void MemoryObjectCache::Invalidate(const std::string& key) - { -#if !defined(__EMSCRIPTEN__) - // Make sure no accessor is currently open (as it may correspond - // to the key to remove) - WriterLock contentLock(contentMutex_); - - // Lock the global structure of the cache - boost::mutex::scoped_lock cacheLock(cacheMutex_); -#endif - - Item* item = NULL; - if (content_.Contains(key, item)) - { - assert(item != NULL); - const size_t size = item->GetValue().GetMemoryUsage(); - delete item; - - content_.Invalidate(key); - - assert(currentSize_ >= size); - currentSize_ -= size; - } - } - - - MemoryObjectCache::Accessor::Accessor(MemoryObjectCache& cache, - const std::string& key, - bool unique) : - item_(NULL) - { -#if !defined(__EMSCRIPTEN__) - if (unique) - { - writerLock_ = WriterLock(cache.contentMutex_); - } - else - { - readerLock_ = ReaderLock(cache.contentMutex_); - } - - // Lock the global structure of the cache, must be *after* the - // reader/writer lock - cacheLock_ = boost::mutex::scoped_lock(cache.cacheMutex_); -#endif - - if (cache.content_.Contains(key, item_)) - { - cache.content_.MakeMostRecent(key); - } - -#if !defined(__EMSCRIPTEN__) - cacheLock_.unlock(); - - if (item_ == NULL) - { - // This item does not exist in the cache, we can release the - // reader/writer lock - if (unique) - { - writerLock_.unlock(); - } - else - { - readerLock_.unlock(); - } - } -#endif - } - - - ICacheable& MemoryObjectCache::Accessor::GetValue() const - { - if (IsValid()) - { - return item_->GetValue(); - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - const boost::posix_time::ptime& MemoryObjectCache::Accessor::GetTime() const - { - if (IsValid()) - { - return item_->GetTime(); - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryObjectCache.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,112 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ICacheable.h" -#include "LeastRecentlyUsedIndex.h" - -#if !defined(__EMSCRIPTEN__) -// Multithreading is not supported in WebAssembly -# include -# include -#endif - -#include - - -namespace Orthanc -{ - class MemoryObjectCache : public boost::noncopyable - { - private: - class Item; - -#if !defined(__EMSCRIPTEN__) - typedef boost::unique_lock WriterLock; - typedef boost::shared_lock ReaderLock; - - // This mutex protects modifications to the structure of the cache (monitor) - boost::mutex cacheMutex_; - - // This mutex protects modifications to the items that are stored in the cache - boost::shared_mutex contentMutex_; -#endif - - size_t currentSize_; - size_t maxSize_; - LeastRecentlyUsedIndex content_; - - void Recycle(size_t targetSize); - - public: - MemoryObjectCache(); - - ~MemoryObjectCache(); - - size_t GetMaximumSize(); - - void SetMaximumSize(size_t size); - - void Acquire(const std::string& key, - ICacheable* value); - - void Invalidate(const std::string& key); - - class Accessor : public boost::noncopyable - { - private: -#if !defined(__EMSCRIPTEN__) - ReaderLock readerLock_; - WriterLock writerLock_; - boost::mutex::scoped_lock cacheLock_; -#endif - - Item* item_; - - public: - Accessor(MemoryObjectCache& cache, - const std::string& key, - bool unique); - - bool IsValid() const - { - return item_ != NULL; - } - - ICacheable& GetValue() const; - - const boost::posix_time::ptime& GetTime() const; - }; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "MemoryStringCache.h" - -namespace Orthanc -{ - class MemoryStringCache::StringValue : public ICacheable - { - private: - std::string content_; - - public: - StringValue(const std::string& content) : - content_(content) - { - } - - const std::string& GetContent() const - { - return content_; - } - - virtual size_t GetMemoryUsage() const - { - return content_.size(); - } - }; - - - void MemoryStringCache::Add(const std::string& key, - const std::string& value) - { - cache_.Acquire(key, new StringValue(value)); - } - - - bool MemoryStringCache::Fetch(std::string& value, - const std::string& key) - { - MemoryObjectCache::Accessor reader(cache_, key, false /* multiple readers are allowed */); - - if (reader.IsValid()) - { - value = dynamic_cast(reader.GetValue()).GetContent(); - return true; - } - else - { - return false; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/MemoryStringCache.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "MemoryObjectCache.h" - -namespace Orthanc -{ - /** - * Facade object around "MemoryObjectCache" that caches a dictionary - * of strings, using the "fetch/add" paradigm of memcached. - **/ - class MemoryStringCache : public boost::noncopyable - { - private: - class StringValue; - - MemoryObjectCache cache_; - - public: - size_t GetMaximumSize() - { - return cache_.GetMaximumSize(); - } - - void SetMaximumSize(size_t size) - { - cache_.SetMaximumSize(size); - } - - void Add(const std::string& key, - const std::string& value); - - void Invalidate(const std::string& key) - { - cache_.Invalidate(key); - } - - bool Fetch(std::string& value, - const std::string& key); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "SharedArchive.h" - -#include "../Toolbox.h" - - -namespace Orthanc -{ - void SharedArchive::RemoveInternal(const std::string& id) - { - Archive::iterator it = archive_.find(id); - - if (it != archive_.end()) - { - delete it->second; - archive_.erase(it); - - lru_.Invalidate(id); - } - } - - - SharedArchive::Accessor::Accessor(SharedArchive& that, - const std::string& id) : - lock_(that.mutex_) - { - Archive::iterator it = that.archive_.find(id); - - if (it == that.archive_.end()) - { - item_ = NULL; - } - else - { - that.lru_.MakeMostRecent(id); - item_ = it->second; - } - } - - - IDynamicObject& SharedArchive::Accessor::GetItem() const - { - if (item_ == NULL) - { - // "IsValid()" should have been called - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return *item_; - } - } - - - SharedArchive::SharedArchive(size_t maxSize) : - maxSize_(maxSize) - { - if (maxSize == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - SharedArchive::~SharedArchive() - { - for (Archive::iterator it = archive_.begin(); - it != archive_.end(); ++it) - { - delete it->second; - } - } - - - std::string SharedArchive::Add(IDynamicObject* obj) - { - boost::mutex::scoped_lock lock(mutex_); - - if (archive_.size() == maxSize_) - { - // The quota has been reached, remove the oldest element - RemoveInternal(lru_.GetOldest()); - } - - std::string id = Toolbox::GenerateUuid(); - RemoveInternal(id); // Should never be useful because of UUID - - archive_[id] = obj; - lru_.Add(id); - - return id; - } - - - void SharedArchive::Remove(const std::string& id) - { - boost::mutex::scoped_lock lock(mutex_); - RemoveInternal(id); - } - - - void SharedArchive::List(std::list& items) - { - items.clear(); - - { - boost::mutex::scoped_lock lock(mutex_); - - for (Archive::const_iterator it = archive_.begin(); - it != archive_.end(); ++it) - { - items.push_back(it->first); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Cache/SharedArchive.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The class SharedArchive cannot be used in sandboxed environments -#endif - -#include "LeastRecentlyUsedIndex.h" -#include "../IDynamicObject.h" - -#include -#include - -namespace Orthanc -{ - class SharedArchive : public boost::noncopyable - { - private: - typedef std::map Archive; - - size_t maxSize_; - boost::mutex mutex_; - Archive archive_; - LeastRecentlyUsedIndex lru_; - - void RemoveInternal(const std::string& id); - - public: - class Accessor : public boost::noncopyable - { - private: - boost::mutex::scoped_lock lock_; - IDynamicObject* item_; - - public: - Accessor(SharedArchive& that, - const std::string& id); - - bool IsValid() const - { - return item_ != NULL; - } - - IDynamicObject& GetItem() const; - }; - - - SharedArchive(size_t maxSize); - - ~SharedArchive(); - - std::string Add(IDynamicObject* obj); // Takes the ownership - - void Remove(const std::string& id); - - void List(std::list& items); - }; -} - - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,116 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "ChunkedBuffer.h" - -#include -#include - - -namespace Orthanc -{ - void ChunkedBuffer::Clear() - { - numBytes_ = 0; - - for (Chunks::iterator it = chunks_.begin(); - it != chunks_.end(); ++it) - { - delete *it; - } - } - - - void ChunkedBuffer::AddChunk(const void* chunkData, - size_t chunkSize) - { - if (chunkSize == 0) - { - return; - } - else - { - assert(chunkData != NULL); - chunks_.push_back(new std::string(reinterpret_cast(chunkData), chunkSize)); - numBytes_ += chunkSize; - } - } - - - void ChunkedBuffer::AddChunk(const std::string& chunk) - { - if (chunk.size() > 0) - { - AddChunk(&chunk[0], chunk.size()); - } - } - - - void ChunkedBuffer::AddChunkDestructive(std::string& chunk) - { - size_t chunkSize = chunk.size(); - - if (chunkSize > 0) - { - chunks_.push_back(new std::string); - chunks_.back()->swap(chunk); - numBytes_ += chunkSize; - } - } - - - void ChunkedBuffer::Flatten(std::string& result) - { - result.resize(numBytes_); - - size_t pos = 0; - for (Chunks::iterator it = chunks_.begin(); - it != chunks_.end(); ++it) - { - assert(*it != NULL); - - size_t s = (*it)->size(); - if (s != 0) - { - memcpy(&result[pos], (*it)->c_str(), s); - pos += s; - } - - delete *it; - } - - chunks_.clear(); - numBytes_ = 0; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/ChunkedBuffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include - -namespace Orthanc -{ - class ChunkedBuffer - { - private: - typedef std::list Chunks; - size_t numBytes_; - Chunks chunks_; - - void Clear(); - - public: - ChunkedBuffer() : numBytes_(0) - { - } - - ~ChunkedBuffer() - { - Clear(); - } - - size_t GetNumBytes() const - { - return numBytes_; - } - - void AddChunk(const void* chunkData, - size_t chunkSize); - - void AddChunk(const std::string& chunk); - - // The source content will be emptied - void AddChunkDestructive(std::string& chunk); - - void Flatten(std::string& result); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compatibility.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compatibility.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compatibility.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compatibility.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -//#define Orthanc_Compatibility_h_STR2(x) #x -//#define Orthanc_Compatibility_h_STR1(x) Orthanc_Compatibility_h_STR2(x) - -//#pragma message("__cplusplus = " Orthanc_Compatibility_h_STR1(__cplusplus)) - -#if (defined _MSC_VER) -//# pragma message("_MSC_VER = " Orthanc_Compatibility_h_STR1(_MSC_VER)) -//# pragma message("_MSVC_LANG = " Orthanc_Compatibility_h_STR1(_MSVC_LANG)) -// The __cplusplus macro cannot be used in Visual C++ < 1914 (VC++ 15.7) -// However, even in recent versions, __cplusplus will only be correct (that is, -// correctly defines the supported C++ version) if a special flag is passed to -// the compiler ("/Zc:__cplusplus") -// To make this header more robust, we use the _MSVC_LANG equivalent macro. - -// please note that not all C++11 features are supported when _MSC_VER == 1600 -// (or higher). This header file can be made for fine-grained, if required, -// based on specific _MSC_VER values - -# if _MSC_VER >= 1600 -# define ORTHANC_Cxx03_DETECTED 0 -# else -# define ORTHANC_Cxx03_DETECTED 1 -# endif - -#else -// of _MSC_VER is not defined, we assume __cplusplus is correctly defined -// if __cplusplus is not defined (very old compilers??), then the following -// test will compare 0 < 201103L and will be true --> safe. -# if __cplusplus < 201103L -# define ORTHANC_Cxx03_DETECTED 1 -# else -# define ORTHANC_Cxx03_DETECTED 0 -# endif -#endif - -#if ORTHANC_Cxx03_DETECTED == 1 -//#pragma message("C++ 11 support is not present.") - -/** - * "std::unique_ptr" was introduced in C++11, and "std::auto_ptr" was - * removed in C++17. We emulate "std::auto_ptr" using boost: "The - * smart pointer unique_ptr [is] a drop-in replacement for - * std::unique_ptr, usable also from C++03 compilers." This is only - * available if Boost >= 1.57.0 (from November 2014). - * https://www.boost.org/doc/libs/1_57_0/doc/html/move/reference.html#header.boost.move.unique_ptr_hpp - **/ - -#include - -namespace std -{ - template - class unique_ptr : public boost::movelib::unique_ptr - { - public: - explicit unique_ptr() : - boost::movelib::unique_ptr() - { - } - - explicit unique_ptr(T* p) : - boost::movelib::unique_ptr(p) - { - } - }; -} -#else -//# pragma message("C++ 11 support is present.") -# include -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DeflateBaseCompressor.h" - -#include "../OrthancException.h" -#include "../Logging.h" - -#include - -namespace Orthanc -{ - void DeflateBaseCompressor::SetCompressionLevel(uint8_t level) - { - if (level >= 10) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Zlib compression level must be between 0 (no compression) and 9 (highest compression)"); - } - - compressionLevel_ = level; - } - - - uint64_t DeflateBaseCompressor::ReadUncompressedSizePrefix(const void* compressed, - size_t compressedSize) - { - if (compressedSize == 0) - { - return 0; - } - - if (compressedSize < sizeof(uint64_t)) - { - throw OrthancException(ErrorCode_CorruptedFile, "The compressed buffer is ill-formed"); - } - - uint64_t size; - memcpy(&size, compressed, sizeof(uint64_t)); - - return size; - } - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/DeflateBaseCompressor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IBufferCompressor.h" - -#if !defined(ORTHANC_ENABLE_ZLIB) -# error The macro ORTHANC_ENABLE_ZLIB must be defined -#endif - -#if ORTHANC_ENABLE_ZLIB != 1 -# error ZLIB support must be enabled to include this file -#endif - - -#include - -namespace Orthanc -{ - class DeflateBaseCompressor : public IBufferCompressor - { - private: - uint8_t compressionLevel_; - bool prefixWithUncompressedSize_; - - protected: - uint64_t ReadUncompressedSizePrefix(const void* compressed, - size_t compressedSize); - - public: - DeflateBaseCompressor() : - compressionLevel_(6), - prefixWithUncompressedSize_(false) - { - } - - void SetCompressionLevel(uint8_t level); - - void SetPrefixWithUncompressedSize(bool prefix) - { - prefixWithUncompressedSize_ = prefix; - } - - bool HasPrefixWithUncompressedSize() const - { - return prefixWithUncompressedSize_; - } - - uint8_t GetCompressionLevel() const - { - return compressionLevel_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "GzipCompressor.h" - -#include -#include -#include - -#include "../OrthancException.h" -#include "../Logging.h" - -namespace Orthanc -{ - uint64_t GzipCompressor::GuessUncompressedSize(const void* compressed, - size_t compressedSize) - { - /** - * "Is there a way to find out the size of the original file which - * is inside a GZIP file? [...] There is no truly reliable way, - * other than gunzipping the stream. You do not need to save the - * result of the decompression, so you can determine the size by - * simply reading and decoding the entire file without taking up - * space with the decompressed result. - * - * There is an unreliable way to determine the uncompressed size, - * which is to look at the last four bytes of the gzip file, which - * is the uncompressed length of that entry modulo 232 in little - * endian order. - * - * It is unreliable because a) the uncompressed data may be longer - * than 2^32 bytes, and b) the gzip file may consist of multiple - * gzip streams, in which case you would find the length of only - * the last of those streams. - * - * If you are in control of the source of the gzip files, you know - * that they consist of single gzip streams, and you know that - * they are less than 2^32 bytes uncompressed, then and only then - * can you use those last four bytes with confidence." - * - * http://stackoverflow.com/a/9727599/881731 - **/ - - if (compressedSize < 4) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - const uint8_t* p = reinterpret_cast(compressed) + compressedSize - 4; - - return ((static_cast(p[0]) << 0) + - (static_cast(p[1]) << 8) + - (static_cast(p[2]) << 16) + - (static_cast(p[3]) << 24)); - } - - - - void GzipCompressor::Compress(std::string& compressed, - const void* uncompressed, - size_t uncompressedSize) - { - uLongf compressedSize = compressBound(static_cast(uncompressedSize)) - + 1024 /* security margin */; - - if (compressedSize == 0) - { - compressedSize = 1; - } - - uint8_t* target; - if (HasPrefixWithUncompressedSize()) - { - compressed.resize(compressedSize + sizeof(uint64_t)); - target = reinterpret_cast(&compressed[0]) + sizeof(uint64_t); - } - else - { - compressed.resize(compressedSize); - target = reinterpret_cast(&compressed[0]); - } - - z_stream stream; - memset(&stream, 0, sizeof(stream)); - - stream.next_in = const_cast(reinterpret_cast(uncompressed)); - stream.next_out = reinterpret_cast(target); - - stream.avail_in = static_cast(uncompressedSize); - stream.avail_out = static_cast(compressedSize); - - // Ensure no overflow (if the buffer is too large for the current archicture) - if (static_cast(stream.avail_in) != uncompressedSize || - static_cast(stream.avail_out) != compressedSize) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - // Initialize the compression engine - int error = deflateInit2(&stream, - GetCompressionLevel(), - Z_DEFLATED, - MAX_WBITS + 16, // ask for gzip output - 8, // default memory level - Z_DEFAULT_STRATEGY); - - if (error != Z_OK) - { - // Cannot initialize zlib - compressed.clear(); - throw OrthancException(ErrorCode_InternalError); - } - - // Compress the input buffer - error = deflate(&stream, Z_FINISH); - - if (error != Z_STREAM_END) - { - deflateEnd(&stream); - compressed.clear(); - - switch (error) - { - case Z_MEM_ERROR: - throw OrthancException(ErrorCode_NotEnoughMemory); - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - size_t size = stream.total_out; - - if (deflateEnd(&stream) != Z_OK) - { - throw OrthancException(ErrorCode_InternalError); - } - - // The compression was successful - if (HasPrefixWithUncompressedSize()) - { - uint64_t s = static_cast(uncompressedSize); - memcpy(&compressed[0], &s, sizeof(uint64_t)); - compressed.resize(size + sizeof(uint64_t)); - } - else - { - compressed.resize(size); - } - } - - - void GzipCompressor::Uncompress(std::string& uncompressed, - const void* compressed, - size_t compressedSize) - { - uint64_t uncompressedSize; - const uint8_t* source = reinterpret_cast(compressed); - - if (HasPrefixWithUncompressedSize()) - { - uncompressedSize = ReadUncompressedSizePrefix(compressed, compressedSize); - source += sizeof(uint64_t); - compressedSize -= sizeof(uint64_t); - } - else - { - uncompressedSize = GuessUncompressedSize(compressed, compressedSize); - } - - try - { - uncompressed.resize(static_cast(uncompressedSize)); - } - catch (...) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - z_stream stream; - memset(&stream, 0, sizeof(stream)); - - char dummy = '\0'; // zlib does not like NULL output buffers (even if the uncompressed data is empty) - stream.next_in = const_cast(source); - stream.next_out = reinterpret_cast(uncompressedSize == 0 ? &dummy : &uncompressed[0]); - - stream.avail_in = static_cast(compressedSize); - stream.avail_out = static_cast(uncompressedSize); - - // Ensure no overflow (if the buffer is too large for the current archicture) - if (static_cast(stream.avail_in) != compressedSize || - static_cast(stream.avail_out) != uncompressedSize) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - // Initialize the compression engine - int error = inflateInit2(&stream, - MAX_WBITS + 16); // this is a gzip input - - if (error != Z_OK) - { - // Cannot initialize zlib - uncompressed.clear(); - throw OrthancException(ErrorCode_InternalError); - } - - // Uncompress the input buffer - error = inflate(&stream, Z_FINISH); - - if (error != Z_STREAM_END) - { - inflateEnd(&stream); - uncompressed.clear(); - - switch (error) - { - case Z_MEM_ERROR: - throw OrthancException(ErrorCode_NotEnoughMemory); - - case Z_BUF_ERROR: - case Z_NEED_DICT: - throw OrthancException(ErrorCode_BadFileFormat); - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - size_t size = stream.total_out; - - if (inflateEnd(&stream) != Z_OK) - { - uncompressed.clear(); - throw OrthancException(ErrorCode_InternalError); - } - - if (size != uncompressedSize) - { - uncompressed.clear(); - - // The uncompressed size was not that properly guess, presumably - // because of a file size over 4GB. Should fallback to - // stream-based decompression. - throw OrthancException(ErrorCode_NotImplemented, - "The uncompressed size of a gzip-encoded buffer was not properly guessed"); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/GzipCompressor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DeflateBaseCompressor.h" - -namespace Orthanc -{ - class GzipCompressor : public DeflateBaseCompressor - { - private: - uint64_t GuessUncompressedSize(const void* compressed, - size_t compressedSize); - - public: - GzipCompressor() - { - SetPrefixWithUncompressedSize(false); - } - - virtual void Compress(std::string& compressed, - const void* uncompressed, - size_t uncompressedSize); - - virtual void Uncompress(std::string& uncompressed, - const void* compressed, - size_t compressedSize); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "HierarchicalZipWriter.h" - -#include "../Toolbox.h" -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - std::string HierarchicalZipWriter::Index::KeepAlphanumeric(const std::string& source) - { - std::string result; - - bool lastSpace = false; - - result.reserve(source.size()); - for (size_t i = 0; i < source.size(); i++) - { - char c = source[i]; - if (c == '^') - c = ' '; - - if (c <= 127 && - c >= 0) - { - if (isspace(c)) - { - if (!lastSpace) - { - lastSpace = true; - result.push_back(' '); - } - } - else if (isalnum(c) || - c == '.' || - c == '_') - { - result.push_back(c); - lastSpace = false; - } - } - } - - return Toolbox::StripSpaces(result); - } - - std::string HierarchicalZipWriter::Index::GetCurrentDirectoryPath() const - { - std::string result; - - Stack::const_iterator it = stack_.begin(); - ++it; // Skip the root node (to avoid absolute paths) - - while (it != stack_.end()) - { - result += (*it)->name_ + "/"; - ++it; - } - - return result; - } - - std::string HierarchicalZipWriter::Index::EnsureUniqueFilename(const char* filename) - { - std::string standardized = KeepAlphanumeric(filename); - - Directory& d = *stack_.back(); - Directory::Content::iterator it = d.content_.find(standardized); - - if (it == d.content_.end()) - { - d.content_[standardized] = 1; - return standardized; - } - else - { - it->second++; - return standardized + "-" + boost::lexical_cast(it->second); - } - } - - HierarchicalZipWriter::Index::Index() - { - stack_.push_back(new Directory); - } - - HierarchicalZipWriter::Index::~Index() - { - for (Stack::iterator it = stack_.begin(); it != stack_.end(); ++it) - { - delete *it; - } - } - - std::string HierarchicalZipWriter::Index::OpenFile(const char* name) - { - return GetCurrentDirectoryPath() + EnsureUniqueFilename(name); - } - - void HierarchicalZipWriter::Index::OpenDirectory(const char* name) - { - std::string d = EnsureUniqueFilename(name); - - // Push the new directory onto the stack - stack_.push_back(new Directory); - stack_.back()->name_ = d; - } - - void HierarchicalZipWriter::Index::CloseDirectory() - { - if (IsRoot()) - { - // Cannot close the root node - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - delete stack_.back(); - stack_.pop_back(); - } - - - HierarchicalZipWriter::HierarchicalZipWriter(const char* path) - { - writer_.SetOutputPath(path); - writer_.Open(); - } - - HierarchicalZipWriter::~HierarchicalZipWriter() - { - writer_.Close(); - } - - void HierarchicalZipWriter::OpenFile(const char* name) - { - std::string p = indexer_.OpenFile(name); - writer_.OpenFile(p.c_str()); - } - - void HierarchicalZipWriter::OpenDirectory(const char* name) - { - indexer_.OpenDirectory(name); - } - - void HierarchicalZipWriter::CloseDirectory() - { - indexer_.CloseDirectory(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/HierarchicalZipWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ZipWriter.h" - -#include -#include -#include - -#if ORTHANC_BUILD_UNIT_TESTS == 1 -# include -#endif - -namespace Orthanc -{ - class HierarchicalZipWriter - { -#if ORTHANC_BUILD_UNIT_TESTS == 1 - FRIEND_TEST(HierarchicalZipWriter, Index); - FRIEND_TEST(HierarchicalZipWriter, Filenames); -#endif - - private: - class Index - { - private: - struct Directory - { - typedef std::map Content; - - std::string name_; - Content content_; - }; - - typedef std::list Stack; - - Stack stack_; - - std::string EnsureUniqueFilename(const char* filename); - - public: - Index(); - - ~Index(); - - bool IsRoot() const - { - return stack_.size() == 1; - } - - std::string OpenFile(const char* name); - - void OpenDirectory(const char* name); - - void CloseDirectory(); - - std::string GetCurrentDirectoryPath() const; - - static std::string KeepAlphanumeric(const std::string& source); - }; - - Index indexer_; - ZipWriter writer_; - - public: - HierarchicalZipWriter(const char* path); - - ~HierarchicalZipWriter(); - - void SetZip64(bool isZip64) - { - writer_.SetZip64(isZip64); - } - - bool IsZip64() const - { - return writer_.IsZip64(); - } - - void SetCompressionLevel(uint8_t level) - { - writer_.SetCompressionLevel(level); - } - - uint8_t GetCompressionLevel() const - { - return writer_.GetCompressionLevel(); - } - - void SetAppendToExisting(bool append) - { - writer_.SetAppendToExisting(append); - } - - bool IsAppendToExisting() const - { - return writer_.IsAppendToExisting(); - } - - void OpenFile(const char* name); - - void OpenDirectory(const char* name); - - void CloseDirectory(); - - std::string GetCurrentDirectoryPath() const - { - return indexer_.GetCurrentDirectoryPath(); - } - - void Write(const void* data, size_t length) - { - writer_.Write(data, length); - } - - void Write(const std::string& data) - { - writer_.Write(data); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/IBufferCompressor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/IBufferCompressor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/IBufferCompressor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/IBufferCompressor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include - -namespace Orthanc -{ - class IBufferCompressor : public boost::noncopyable - { - public: - virtual ~IBufferCompressor() - { - } - - virtual void Compress(std::string& compressed, - const void* uncompressed, - size_t uncompressedSize) = 0; - - virtual void Uncompress(std::string& uncompressed, - const void* compressed, - size_t compressedSize) = 0; - - static void Compress(std::string& compressed, - IBufferCompressor& compressor, - const std::string& uncompressed) - { - compressor.Compress(compressed, - uncompressed.size() == 0 ? NULL : uncompressed.c_str(), - uncompressed.size()); - } - - static void Uncompress(std::string& uncompressed, - IBufferCompressor& compressor, - const std::string& compressed) - { - compressor.Uncompress(uncompressed, - compressed.size() == 0 ? NULL : compressed.c_str(), - compressed.size()); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,262 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "ZipWriter.h" - -#include -#include -#include - -#include "../../Resources/ThirdParty/minizip/zip.h" -#include "../OrthancException.h" -#include "../Logging.h" - - -static void PrepareFileInfo(zip_fileinfo& zfi) -{ - memset(&zfi, 0, sizeof(zfi)); - - using namespace boost::posix_time; - ptime now = second_clock::local_time(); - - boost::gregorian::date today = now.date(); - ptime midnight(today); - - time_duration sinceMidnight = now - midnight; - zfi.tmz_date.tm_sec = static_cast(sinceMidnight.seconds()); // seconds after the minute - [0,59] - zfi.tmz_date.tm_min = static_cast(sinceMidnight.minutes()); // minutes after the hour - [0,59] - zfi.tmz_date.tm_hour = static_cast(sinceMidnight.hours()); // hours since midnight - [0,23] - - // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/gregorian/greg_day.html - zfi.tmz_date.tm_mday = today.day(); // day of the month - [1,31] - - // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/gregorian/greg_month.html - zfi.tmz_date.tm_mon = today.month() - 1; // months since January - [0,11] - - // http://www.boost.org/doc/libs/1_35_0/doc/html/boost/gregorian/greg_year.html - zfi.tmz_date.tm_year = today.year(); // years - [1980..2044] -} - - - -namespace Orthanc -{ - struct ZipWriter::PImpl - { - zipFile file_; - - PImpl() : file_(NULL) - { - } - }; - - ZipWriter::ZipWriter() : - pimpl_(new PImpl), - isZip64_(false), - hasFileInZip_(false), - append_(false), - compressionLevel_(6) - { - } - - ZipWriter::~ZipWriter() - { - Close(); - } - - void ZipWriter::Close() - { - if (IsOpen()) - { - zipClose(pimpl_->file_, "Created by Orthanc"); - pimpl_->file_ = NULL; - hasFileInZip_ = false; - } - } - - bool ZipWriter::IsOpen() const - { - return pimpl_->file_ != NULL; - } - - void ZipWriter::Open() - { - if (IsOpen()) - { - return; - } - - if (path_.size() == 0) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Please call SetOutputPath() before creating the file"); - } - - hasFileInZip_ = false; - - int mode = APPEND_STATUS_CREATE; - if (append_ && - boost::filesystem::exists(path_)) - { - mode = APPEND_STATUS_ADDINZIP; - } - - if (isZip64_) - { - pimpl_->file_ = zipOpen64(path_.c_str(), mode); - } - else - { - pimpl_->file_ = zipOpen(path_.c_str(), mode); - } - - if (!pimpl_->file_) - { - throw OrthancException(ErrorCode_CannotWriteFile, - "Cannot create new ZIP archive: " + path_); - } - } - - void ZipWriter::SetOutputPath(const char* path) - { - Close(); - path_ = path; - } - - void ZipWriter::SetZip64(bool isZip64) - { - Close(); - isZip64_ = isZip64; - } - - void ZipWriter::SetCompressionLevel(uint8_t level) - { - if (level >= 10) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "ZIP compression level must be between 0 (no compression) " - "and 9 (highest compression)"); - } - - Close(); - compressionLevel_ = level; - } - - void ZipWriter::OpenFile(const char* path) - { - Open(); - - zip_fileinfo zfi; - PrepareFileInfo(zfi); - - int result; - - if (isZip64_) - { - result = zipOpenNewFileInZip64(pimpl_->file_, path, - &zfi, - NULL, 0, - NULL, 0, - "", // Comment - Z_DEFLATED, - compressionLevel_, 1); - } - else - { - result = zipOpenNewFileInZip(pimpl_->file_, path, - &zfi, - NULL, 0, - NULL, 0, - "", // Comment - Z_DEFLATED, - compressionLevel_); - } - - if (result != 0) - { - throw OrthancException(ErrorCode_CannotWriteFile, - "Cannot add new file inside ZIP archive: " + std::string(path)); - } - - hasFileInZip_ = true; - } - - - void ZipWriter::Write(const std::string& data) - { - if (data.size()) - { - Write(&data[0], data.size()); - } - } - - - void ZipWriter::Write(const void* data, size_t length) - { - if (!hasFileInZip_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, "Call first OpenFile()"); - } - - const size_t maxBytesInAStep = std::numeric_limits::max(); - - const char* p = reinterpret_cast(data); - - while (length > 0) - { - int bytes = static_cast(length <= maxBytesInAStep ? length : maxBytesInAStep); - - if (zipWriteInFileInZip(pimpl_->file_, p, bytes)) - { - throw OrthancException(ErrorCode_CannotWriteFile, - "Cannot write data to ZIP archive: " + path_); - } - - p += bytes; - length -= bytes; - } - } - - - void ZipWriter::SetAppendToExisting(bool append) - { - Close(); - append_ = append; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZipWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_ZLIB) -# error The macro ORTHANC_ENABLE_ZLIB must be defined -#endif - -#if ORTHANC_ENABLE_ZLIB != 1 -# error ZLIB support must be enabled to include this file -#endif - - -#include -#include -#include - -namespace Orthanc -{ - class ZipWriter - { - private: - struct PImpl; - boost::shared_ptr pimpl_; - - bool isZip64_; - bool hasFileInZip_; - bool append_; - uint8_t compressionLevel_; - std::string path_; - - public: - ZipWriter(); - - ~ZipWriter(); - - void SetZip64(bool isZip64); - - bool IsZip64() const - { - return isZip64_; - } - - void SetCompressionLevel(uint8_t level); - - uint8_t GetCompressionLevel() const - { - return compressionLevel_; - } - - void SetAppendToExisting(bool append); - - bool IsAppendToExisting() const - { - return append_; - } - - void Open(); - - void Close(); - - bool IsOpen() const; - - void SetOutputPath(const char* path); - - const std::string& GetOutputPath() const - { - return path_; - } - - void OpenFile(const char* path); - - void Write(const void* data, size_t length); - - void Write(const std::string& data); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ZlibCompressor.h" - -#include "../OrthancException.h" -#include "../Logging.h" - -#include -#include -#include - -namespace Orthanc -{ - void ZlibCompressor::Compress(std::string& compressed, - const void* uncompressed, - size_t uncompressedSize) - { - if (uncompressedSize == 0) - { - compressed.clear(); - return; - } - - uLongf compressedSize = compressBound(static_cast(uncompressedSize)) - + 1024 /* security margin */; - if (compressedSize == 0) - { - compressedSize = 1; - } - - uint8_t* target; - if (HasPrefixWithUncompressedSize()) - { - compressed.resize(compressedSize + sizeof(uint64_t)); - target = reinterpret_cast(&compressed[0]) + sizeof(uint64_t); - } - else - { - compressed.resize(compressedSize); - target = reinterpret_cast(&compressed[0]); - } - - int error = compress2(target, - &compressedSize, - const_cast(static_cast(uncompressed)), - static_cast(uncompressedSize), - GetCompressionLevel()); - - if (error != Z_OK) - { - compressed.clear(); - - switch (error) - { - case Z_MEM_ERROR: - throw OrthancException(ErrorCode_NotEnoughMemory); - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - // The compression was successful - if (HasPrefixWithUncompressedSize()) - { - uint64_t s = static_cast(uncompressedSize); - memcpy(&compressed[0], &s, sizeof(uint64_t)); - compressed.resize(compressedSize + sizeof(uint64_t)); - } - else - { - compressed.resize(compressedSize); - } - } - - - void ZlibCompressor::Uncompress(std::string& uncompressed, - const void* compressed, - size_t compressedSize) - { - if (compressedSize == 0) - { - uncompressed.clear(); - return; - } - - if (!HasPrefixWithUncompressedSize()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot guess the uncompressed size of a zlib-encoded buffer"); - } - - uint64_t uncompressedSize = ReadUncompressedSizePrefix(compressed, compressedSize); - - try - { - uncompressed.resize(static_cast(uncompressedSize)); - } - catch (...) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - uLongf tmp = static_cast(uncompressedSize); - int error = uncompress - (reinterpret_cast(&uncompressed[0]), - &tmp, - reinterpret_cast(compressed) + sizeof(uint64_t), - static_cast(compressedSize - sizeof(uint64_t))); - - if (error != Z_OK) - { - uncompressed.clear(); - - switch (error) - { - case Z_DATA_ERROR: - throw OrthancException(ErrorCode_CorruptedFile); - - case Z_MEM_ERROR: - throw OrthancException(ErrorCode_NotEnoughMemory); - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Compression/ZlibCompressor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DeflateBaseCompressor.h" - -namespace Orthanc -{ - class ZlibCompressor : public DeflateBaseCompressor - { - public: - ZlibCompressor() - { - SetPrefixWithUncompressedSize(true); - } - - virtual void Compress(std::string& compressed, - const void* uncompressed, - size_t uncompressedSize); - - virtual void Uncompress(std::string& uncompressed, - const void* compressed, - size_t compressedSize); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomArray.h" - -#include - -namespace Orthanc -{ - DicomArray::DicomArray(const DicomMap& map) - { - elements_.reserve(map.content_.size()); - - for (DicomMap::Content::const_iterator it = - map.content_.begin(); it != map.content_.end(); ++it) - { - elements_.push_back(new DicomElement(it->first, *it->second)); - } - } - - - DicomArray::~DicomArray() - { - for (size_t i = 0; i < elements_.size(); i++) - { - delete elements_[i]; - } - } - - - void DicomArray::Print(FILE* fp) const - { - for (size_t i = 0; i < elements_.size(); i++) - { - DicomTag t = elements_[i]->GetTag(); - const DicomValue& v = elements_[i]->GetValue(); - std::string s = v.IsNull() ? "(null)" : v.GetContent(); - printf("0x%04x 0x%04x [%s]\n", t.GetGroup(), t.GetElement(), s.c_str()); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomArray.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomElement.h" -#include "DicomMap.h" - -#include - -namespace Orthanc -{ - class DicomArray : public boost::noncopyable - { - private: - typedef std::vector Elements; - - Elements elements_; - - public: - explicit DicomArray(const DicomMap& map); - - ~DicomArray(); - - size_t GetSize() const - { - return elements_.size(); - } - - const DicomElement& GetElement(size_t i) const - { - return *elements_[i]; - } - - void Print(FILE* fp) const; // For debugging only - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomElement.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomElement.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomElement.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomElement.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomValue.h" -#include "DicomTag.h" - -namespace Orthanc -{ - class DicomElement : public boost::noncopyable - { - private: - DicomTag tag_; - DicomValue* value_; - - public: - DicomElement(uint16_t group, - uint16_t element, - const DicomValue& value) : - tag_(group, element), - value_(value.Clone()) - { - } - - DicomElement(const DicomTag& tag, - const DicomValue& value) : - tag_(tag), - value_(value.Clone()) - { - } - - ~DicomElement() - { - delete value_; - } - - const DicomTag& GetTag() const - { - return tag_; - } - - const DicomValue& GetValue() const - { - return *value_; - } - - uint16_t GetTagGroup() const - { - return tag_.GetGroup(); - } - - uint16_t GetTagElement() const - { - return tag_.GetElement(); - } - - bool operator< (const DicomElement& other) const - { - return GetTag() < other.GetTag(); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,310 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "DicomImageInformation.h" - -#include "../Compatibility.h" -#include "../OrthancException.h" -#include "../Toolbox.h" -#include -#include -#include -#include -#include - -namespace Orthanc -{ - DicomImageInformation::DicomImageInformation(const DicomMap& values) - { - unsigned int pixelRepresentation; - unsigned int planarConfiguration = 0; - - try - { - std::string p = values.GetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION).GetContent(); - Toolbox::ToUpperCase(p); - - if (p == "RGB") - { - photometric_ = PhotometricInterpretation_RGB; - } - else if (p == "MONOCHROME1") - { - photometric_ = PhotometricInterpretation_Monochrome1; - } - else if (p == "MONOCHROME2") - { - photometric_ = PhotometricInterpretation_Monochrome2; - } - else if (p == "PALETTE COLOR") - { - photometric_ = PhotometricInterpretation_Palette; - } - else if (p == "HSV") - { - photometric_ = PhotometricInterpretation_HSV; - } - else if (p == "ARGB") - { - photometric_ = PhotometricInterpretation_ARGB; - } - else if (p == "CMYK") - { - photometric_ = PhotometricInterpretation_CMYK; - } - else if (p == "YBR_FULL") - { - photometric_ = PhotometricInterpretation_YBRFull; - } - else if (p == "YBR_FULL_422") - { - photometric_ = PhotometricInterpretation_YBRFull422; - } - else if (p == "YBR_PARTIAL_420") - { - photometric_ = PhotometricInterpretation_YBRPartial420; - } - else if (p == "YBR_PARTIAL_422") - { - photometric_ = PhotometricInterpretation_YBRPartial422; - } - else if (p == "YBR_ICT") - { - photometric_ = PhotometricInterpretation_YBR_ICT; - } - else if (p == "YBR_RCT") - { - photometric_ = PhotometricInterpretation_YBR_RCT; - } - else - { - photometric_ = PhotometricInterpretation_Unknown; - } - - values.GetValue(DICOM_TAG_COLUMNS).ParseFirstUnsignedInteger(width_); // in some US images, we've seen tag values of "800\0"; that's why we parse the 'first' value - values.GetValue(DICOM_TAG_ROWS).ParseFirstUnsignedInteger(height_); - - bitsAllocated_ = boost::lexical_cast(values.GetValue(DICOM_TAG_BITS_ALLOCATED).GetContent()); - - try - { - samplesPerPixel_ = boost::lexical_cast(values.GetValue(DICOM_TAG_SAMPLES_PER_PIXEL).GetContent()); - } - catch (OrthancException&) - { - samplesPerPixel_ = 1; // Assume 1 color channel - } - - try - { - bitsStored_ = boost::lexical_cast(values.GetValue(DICOM_TAG_BITS_STORED).GetContent()); - } - catch (OrthancException&) - { - bitsStored_ = bitsAllocated_; - } - - try - { - highBit_ = boost::lexical_cast(values.GetValue(DICOM_TAG_HIGH_BIT).GetContent()); - } - catch (OrthancException&) - { - highBit_ = bitsStored_ - 1; - } - - try - { - pixelRepresentation = boost::lexical_cast(values.GetValue(DICOM_TAG_PIXEL_REPRESENTATION).GetContent()); - } - catch (OrthancException&) - { - pixelRepresentation = 0; // Assume unsigned pixels - } - - if (samplesPerPixel_ > 1) - { - // The "Planar Configuration" is only set when "Samples per Pixels" is greater than 1 - // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.3.1.3 - try - { - planarConfiguration = boost::lexical_cast(values.GetValue(DICOM_TAG_PLANAR_CONFIGURATION).GetContent()); - } - catch (OrthancException&) - { - planarConfiguration = 0; // Assume interleaved color channels - } - } - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_NotImplemented); - } - catch (OrthancException&) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - if (values.HasTag(DICOM_TAG_NUMBER_OF_FRAMES)) - { - try - { - numberOfFrames_ = boost::lexical_cast(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).GetContent()); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_NotImplemented); - } - } - else - { - numberOfFrames_ = 1; - } - - if (bitsAllocated_ != 8 && bitsAllocated_ != 16 && - bitsAllocated_ != 24 && bitsAllocated_ != 32) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat, "Image not supported: " + boost::lexical_cast(bitsAllocated_) + " bits allocated"); - } - else if (numberOfFrames_ == 0) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat, "Image not supported (no frames)"); - } - else if (planarConfiguration != 0 && planarConfiguration != 1) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat, "Image not supported: planar configuration is " + boost::lexical_cast(planarConfiguration)); - } - - if (samplesPerPixel_ == 0) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat, "Image not supported: samples per pixel is 0"); - } - - bytesPerValue_ = bitsAllocated_ / 8; - - isPlanar_ = (planarConfiguration != 0 ? true : false); - isSigned_ = (pixelRepresentation != 0 ? true : false); - } - - DicomImageInformation* DicomImageInformation::Clone() const - { - std::unique_ptr target(new DicomImageInformation); - target->width_ = width_; - target->height_ = height_; - target->samplesPerPixel_ = samplesPerPixel_; - target->numberOfFrames_ = numberOfFrames_; - target->isPlanar_ = isPlanar_; - target->isSigned_ = isSigned_; - target->bytesPerValue_ = bytesPerValue_; - target->bitsAllocated_ = bitsAllocated_; - target->bitsStored_ = bitsStored_; - target->highBit_ = highBit_; - target->photometric_ = photometric_; - - return target.release(); - } - - bool DicomImageInformation::ExtractPixelFormat(PixelFormat& format, - bool ignorePhotometricInterpretation) const - { - if (photometric_ == PhotometricInterpretation_Palette) - { - if (GetBitsStored() == 8 && GetChannelCount() == 1 && !IsSigned()) - { - format = PixelFormat_RGB24; - return true; - } - - if (GetBitsStored() == 16 && GetChannelCount() == 1 && !IsSigned()) - { - format = PixelFormat_RGB48; - return true; - } - } - - if (ignorePhotometricInterpretation || - photometric_ == PhotometricInterpretation_Monochrome1 || - photometric_ == PhotometricInterpretation_Monochrome2) - { - if (GetBitsStored() == 8 && GetChannelCount() == 1 && !IsSigned()) - { - format = PixelFormat_Grayscale8; - return true; - } - - if (GetBitsAllocated() == 16 && GetChannelCount() == 1 && !IsSigned()) - { - format = PixelFormat_Grayscale16; - return true; - } - - if (GetBitsAllocated() == 16 && GetChannelCount() == 1 && IsSigned()) - { - format = PixelFormat_SignedGrayscale16; - return true; - } - - if (GetBitsAllocated() == 32 && GetChannelCount() == 1 && !IsSigned()) - { - format = PixelFormat_Grayscale32; - return true; - } - } - - if (GetBitsStored() == 8 && - GetChannelCount() == 3 && - !IsSigned() && - (ignorePhotometricInterpretation || photometric_ == PhotometricInterpretation_RGB)) - { - format = PixelFormat_RGB24; - return true; - } - - return false; - } - - - size_t DicomImageInformation::GetFrameSize() const - { - return (GetHeight() * - GetWidth() * - GetBytesPerValue() * - GetChannelCount()); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomImageInformation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomMap.h" - -#include - -namespace Orthanc -{ - class DicomImageInformation - { - private: - unsigned int width_; - unsigned int height_; - unsigned int samplesPerPixel_; - unsigned int numberOfFrames_; - - bool isPlanar_; - bool isSigned_; - size_t bytesPerValue_; - - unsigned int bitsAllocated_; - unsigned int bitsStored_; - unsigned int highBit_; - - PhotometricInterpretation photometric_; - - protected: - explicit DicomImageInformation() - { - } - - public: - explicit DicomImageInformation(const DicomMap& values); - - DicomImageInformation* Clone() const; - - unsigned int GetWidth() const - { - return width_; - } - - unsigned int GetHeight() const - { - return height_; - } - - unsigned int GetNumberOfFrames() const - { - return numberOfFrames_; - } - - unsigned int GetChannelCount() const - { - return samplesPerPixel_; - } - - unsigned int GetBitsStored() const - { - return bitsStored_; - } - - size_t GetBytesPerValue() const - { - return bytesPerValue_; - } - - bool IsSigned() const - { - return isSigned_; - } - - unsigned int GetBitsAllocated() const - { - return bitsAllocated_; - } - - unsigned int GetHighBit() const - { - return highBit_; - } - - bool IsPlanar() const - { - return isPlanar_; - } - - unsigned int GetShift() const - { - return highBit_ + 1 - bitsStored_; - } - - PhotometricInterpretation GetPhotometricInterpretation() const - { - return photometric_; - } - - bool ExtractPixelFormat(PixelFormat& format, - bool ignorePhotometricInterpretation) const; - - size_t GetFrameSize() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomInstanceHasher.h" - -#include "../OrthancException.h" -#include "../Toolbox.h" - -namespace Orthanc -{ - void DicomInstanceHasher::Setup(const std::string& patientId, - const std::string& studyUid, - const std::string& seriesUid, - const std::string& instanceUid) - { - patientId_ = patientId; - studyUid_ = studyUid; - seriesUid_ = seriesUid; - instanceUid_ = instanceUid; - - if (studyUid_.size() == 0 || - seriesUid_.size() == 0 || - instanceUid_.size() == 0) - { - throw OrthancException(ErrorCode_BadFileFormat, "missing StudyInstanceUID, SeriesInstanceUID or SOPInstanceUID"); - } - } - - DicomInstanceHasher::DicomInstanceHasher(const DicomMap& instance) - { - const DicomValue* patientId = instance.TestAndGetValue(DICOM_TAG_PATIENT_ID); - - Setup(patientId == NULL ? "" : patientId->GetContent(), - instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent(), - instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent(), - instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent()); - } - - const std::string& DicomInstanceHasher::HashPatient() - { - if (patientHash_.size() == 0) - { - Toolbox::ComputeSHA1(patientHash_, patientId_); - } - - return patientHash_; - } - - const std::string& DicomInstanceHasher::HashStudy() - { - if (studyHash_.size() == 0) - { - Toolbox::ComputeSHA1(studyHash_, patientId_ + "|" + studyUid_); - } - - return studyHash_; - } - - const std::string& DicomInstanceHasher::HashSeries() - { - if (seriesHash_.size() == 0) - { - Toolbox::ComputeSHA1(seriesHash_, patientId_ + "|" + studyUid_ + "|" + seriesUid_); - } - - return seriesHash_; - } - - const std::string& DicomInstanceHasher::HashInstance() - { - if (instanceHash_.size() == 0) - { - Toolbox::ComputeSHA1(instanceHash_, patientId_ + "|" + studyUid_ + "|" + seriesUid_ + "|" + instanceUid_); - } - - return instanceHash_; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomInstanceHasher.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomMap.h" - -namespace Orthanc -{ - /** - * This class implements the hashing mechanism that is used to - * convert DICOM unique identifiers to Orthanc identifiers. Any - * Orthanc identifier for a DICOM resource corresponds to the SHA-1 - * hash of the DICOM identifiers. - - * \note SHA-1 hash is used because it is less sensitive to - * collision attacks than MD5. [Reference] - **/ - class DicomInstanceHasher - { - private: - std::string patientId_; - std::string studyUid_; - std::string seriesUid_; - std::string instanceUid_; - - std::string patientHash_; - std::string studyHash_; - std::string seriesHash_; - std::string instanceHash_; - - void Setup(const std::string& patientId, - const std::string& studyUid, - const std::string& seriesUid, - const std::string& instanceUid); - - public: - DicomInstanceHasher(const DicomMap& instance); - - DicomInstanceHasher(const std::string& patientId, - const std::string& studyUid, - const std::string& seriesUid, - const std::string& instanceUid) - { - Setup(patientId, studyUid, seriesUid, instanceUid); - } - - const std::string& GetPatientId() const - { - return patientId_; - } - - const std::string& GetStudyUid() const - { - return studyUid_; - } - - const std::string& GetSeriesUid() const - { - return seriesUid_; - } - - const std::string& GetInstanceUid() const - { - return instanceUid_; - } - - const std::string& HashPatient(); - - const std::string& HashStudy(); - - const std::string& HashSeries(); - - const std::string& HashInstance(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,204 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "DicomIntegerPixelAccessor.h" - -#include "../OrthancException.h" -#include -#include -#include -#include - -namespace Orthanc -{ - DicomIntegerPixelAccessor::DicomIntegerPixelAccessor(const DicomMap& values, - const void* pixelData, - size_t size) : - information_(values), - pixelData_(pixelData), - size_(size) - { - if (information_.GetBitsAllocated() > 32 || - information_.GetBitsStored() >= 32) - { - // Not available, as the accessor internally uses int32_t values - throw OrthancException(ErrorCode_NotImplemented); - } - - frame_ = 0; - frameOffset_ = information_.GetFrameSize(); - - if (information_.GetNumberOfFrames() * frameOffset_ > size) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - if (information_.IsSigned()) - { - // Pixels are signed - mask_ = (1 << (information_.GetBitsStored() - 1)) - 1; - signMask_ = (1 << (information_.GetBitsStored() - 1)); - } - else - { - // Pixels are unsigned - mask_ = (1 << information_.GetBitsStored()) - 1; - signMask_ = 0; - } - - if (information_.IsPlanar()) - { - /** - * Each color plane shall be sent contiguously. For RGB images, - * this means the order of the pixel values sent is R1, R2, R3, - * ..., G1, G2, G3, ..., B1, B2, B3, etc. - **/ - rowOffset_ = information_.GetWidth() * information_.GetBytesPerValue(); - } - else - { - /** - * The sample values for the first pixel are followed by the - * sample values for the second pixel, etc. For RGB images, this - * means the order of the pixel values sent shall be R1, G1, B1, - * R2, G2, B2, ..., etc. - **/ - rowOffset_ = information_.GetWidth() * information_.GetBytesPerValue() * information_.GetChannelCount(); - } - } - - - void DicomIntegerPixelAccessor::GetExtremeValues(int32_t& min, - int32_t& max) const - { - if (information_.GetHeight() == 0 || information_.GetWidth() == 0) - { - min = max = 0; - return; - } - - min = std::numeric_limits::max(); - max = std::numeric_limits::min(); - - for (unsigned int y = 0; y < information_.GetHeight(); y++) - { - for (unsigned int x = 0; x < information_.GetWidth(); x++) - { - for (unsigned int c = 0; c < information_.GetChannelCount(); c++) - { - int32_t v = GetValue(x, y); - if (v < min) - min = v; - if (v > max) - max = v; - } - } - } - } - - - int32_t DicomIntegerPixelAccessor::GetValue(unsigned int x, - unsigned int y, - unsigned int channel) const - { - assert(x < information_.GetWidth() && - y < information_.GetHeight() && - channel < information_.GetChannelCount()); - - const uint8_t* pixel = reinterpret_cast(pixelData_) + - y * rowOffset_ + frame_ * frameOffset_; - - // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.3.1.3 - if (information_.IsPlanar()) - { - /** - * Each color plane shall be sent contiguously. For RGB images, - * this means the order of the pixel values sent is R1, R2, R3, - * ..., G1, G2, G3, ..., B1, B2, B3, etc. - **/ - assert(frameOffset_ % information_.GetChannelCount() == 0); - pixel += channel * frameOffset_ / information_.GetChannelCount() + x * information_.GetBytesPerValue(); - } - else - { - /** - * The sample values for the first pixel are followed by the - * sample values for the second pixel, etc. For RGB images, this - * means the order of the pixel values sent shall be R1, G1, B1, - * R2, G2, B2, ..., etc. - **/ - pixel += channel * information_.GetBytesPerValue() + x * information_.GetChannelCount() * information_.GetBytesPerValue(); - } - - uint32_t v; - v = pixel[0]; - if (information_.GetBytesPerValue() >= 2) - v = v + (static_cast(pixel[1]) << 8); - if (information_.GetBytesPerValue() >= 3) - v = v + (static_cast(pixel[2]) << 16); - if (information_.GetBytesPerValue() >= 4) - v = v + (static_cast(pixel[3]) << 24); - - v = v >> information_.GetShift(); - - if (v & signMask_) - { - // Signed value - // http://en.wikipedia.org/wiki/Two%27s_complement#Subtraction_from_2N - return -static_cast(mask_) + static_cast(v & mask_) - 1; - } - else - { - // Unsigned value - return static_cast(v & mask_); - } - } - - - void DicomIntegerPixelAccessor::SetCurrentFrame(unsigned int frame) - { - if (frame >= information_.GetNumberOfFrames()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - frame_ = frame; - } - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomIntegerPixelAccessor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomMap.h" - -#include "DicomImageInformation.h" - -#include - -namespace Orthanc -{ - class DicomIntegerPixelAccessor - { - private: - DicomImageInformation information_; - - uint32_t signMask_; - uint32_t mask_; - - const void* pixelData_; - size_t size_; - unsigned int frame_; - size_t frameOffset_; - size_t rowOffset_; - - public: - DicomIntegerPixelAccessor(const DicomMap& values, - const void* pixelData, - size_t size); - - const DicomImageInformation GetInformation() const - { - return information_; - } - - unsigned int GetCurrentFrame() const - { - return frame_; - } - - void SetCurrentFrame(unsigned int frame); - - void GetExtremeValues(int32_t& min, - int32_t& max) const; - - int32_t GetValue(unsigned int x, unsigned int y, unsigned int channel = 0) const; - - const void* GetPixelData() const - { - return pixelData_; - } - - size_t GetSize() const - { - return size_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1424 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomMap.h" - -#include -#include - -#include "../Compatibility.h" -#include "../Endianness.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "DicomArray.h" - - -namespace Orthanc -{ - namespace - { - struct MainDicomTag - { - const DicomTag tag_; - const char* name_; - }; - } - - static const MainDicomTag PATIENT_MAIN_DICOM_TAGS[] = - { - // { DicomTag(0x0010, 0x1010), "PatientAge" }, - // { DicomTag(0x0010, 0x1040), "PatientAddress" }, - { DicomTag(0x0010, 0x0010), "PatientName" }, - { DicomTag(0x0010, 0x0030), "PatientBirthDate" }, - { DicomTag(0x0010, 0x0040), "PatientSex" }, - { DicomTag(0x0010, 0x1000), "OtherPatientIDs" }, - { DICOM_TAG_PATIENT_ID, "PatientID" } - }; - - static const MainDicomTag STUDY_MAIN_DICOM_TAGS[] = - { - // { DicomTag(0x0010, 0x1020), "PatientSize" }, - // { DicomTag(0x0010, 0x1030), "PatientWeight" }, - { DICOM_TAG_STUDY_DATE, "StudyDate" }, - { DicomTag(0x0008, 0x0030), "StudyTime" }, - { DicomTag(0x0020, 0x0010), "StudyID" }, - { DICOM_TAG_STUDY_DESCRIPTION, "StudyDescription" }, - { DICOM_TAG_ACCESSION_NUMBER, "AccessionNumber" }, - { DICOM_TAG_STUDY_INSTANCE_UID, "StudyInstanceUID" }, - - // New in db v6 - { DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION, "RequestedProcedureDescription" }, - { DICOM_TAG_INSTITUTION_NAME, "InstitutionName" }, - { DICOM_TAG_REQUESTING_PHYSICIAN, "RequestingPhysician" }, - { DICOM_TAG_REFERRING_PHYSICIAN_NAME, "ReferringPhysicianName" } - }; - - static const MainDicomTag SERIES_MAIN_DICOM_TAGS[] = - { - // { DicomTag(0x0010, 0x1080), "MilitaryRank" }, - { DicomTag(0x0008, 0x0021), "SeriesDate" }, - { DicomTag(0x0008, 0x0031), "SeriesTime" }, - { DICOM_TAG_MODALITY, "Modality" }, - { DicomTag(0x0008, 0x0070), "Manufacturer" }, - { DicomTag(0x0008, 0x1010), "StationName" }, - { DICOM_TAG_SERIES_DESCRIPTION, "SeriesDescription" }, - { DicomTag(0x0018, 0x0015), "BodyPartExamined" }, - { DicomTag(0x0018, 0x0024), "SequenceName" }, - { DicomTag(0x0018, 0x1030), "ProtocolName" }, - { DicomTag(0x0020, 0x0011), "SeriesNumber" }, - { DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, "CardiacNumberOfImages" }, - { DICOM_TAG_IMAGES_IN_ACQUISITION, "ImagesInAcquisition" }, - { DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, "NumberOfTemporalPositions" }, - { DICOM_TAG_NUMBER_OF_SLICES, "NumberOfSlices" }, - { DICOM_TAG_NUMBER_OF_TIME_SLICES, "NumberOfTimeSlices" }, - { DICOM_TAG_SERIES_INSTANCE_UID, "SeriesInstanceUID" }, - - // New in db v6 - { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" }, - { DICOM_TAG_SERIES_TYPE, "SeriesType" }, - { DICOM_TAG_OPERATOR_NAME, "OperatorsName" }, - { DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, "PerformedProcedureStepDescription" }, - { DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, "AcquisitionDeviceProcessingDescription" }, - { DICOM_TAG_CONTRAST_BOLUS_AGENT, "ContrastBolusAgent" } - }; - - static const MainDicomTag INSTANCE_MAIN_DICOM_TAGS[] = - { - { DicomTag(0x0008, 0x0012), "InstanceCreationDate" }, - { DicomTag(0x0008, 0x0013), "InstanceCreationTime" }, - { DicomTag(0x0020, 0x0012), "AcquisitionNumber" }, - { DICOM_TAG_IMAGE_INDEX, "ImageIndex" }, - { DICOM_TAG_INSTANCE_NUMBER, "InstanceNumber" }, - { DICOM_TAG_NUMBER_OF_FRAMES, "NumberOfFrames" }, - { DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, "TemporalPositionIdentifier" }, - { DICOM_TAG_SOP_INSTANCE_UID, "SOPInstanceUID" }, - - // New in db v6 - { DICOM_TAG_IMAGE_POSITION_PATIENT, "ImagePositionPatient" }, - { DICOM_TAG_IMAGE_COMMENTS, "ImageComments" }, - - /** - * Main DICOM tags that are not part of any release of the - * database schema yet, and that will be part of future db v7. In - * the meantime, the user must call "/tools/reconstruct" once to - * access these tags if the corresponding DICOM files where - * indexed in the database by an older version of Orthanc. - **/ - { DICOM_TAG_IMAGE_ORIENTATION_PATIENT, "ImageOrientationPatient" } // New in Orthanc 1.4.2 - }; - - - static void LoadMainDicomTags(const MainDicomTag*& tags, - size_t& size, - ResourceType level) - { - switch (level) - { - case ResourceType_Patient: - tags = PATIENT_MAIN_DICOM_TAGS; - size = sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); - break; - - case ResourceType_Study: - tags = STUDY_MAIN_DICOM_TAGS; - size = sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); - break; - - case ResourceType_Series: - tags = SERIES_MAIN_DICOM_TAGS; - size = sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); - break; - - case ResourceType_Instance: - tags = INSTANCE_MAIN_DICOM_TAGS; - size = sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - static void LoadMainDicomTags(std::map& target, - ResourceType level) - { - const MainDicomTag* tags = NULL; - size_t size; - LoadMainDicomTags(tags, size, level); - - assert(tags != NULL && - size != 0); - - for (size_t i = 0; i < size; i++) - { - assert(target.find(tags[i].tag_) == target.end()); - - target[tags[i].tag_] = tags[i].name_; - } - } - - - namespace - { - class DicomTag2 : public DicomTag - { - public: - DicomTag2() : - DicomTag(0, 0) // To make std::map<> happy - { - } - - DicomTag2(const DicomTag& tag) : - DicomTag(tag) - { - } - }; - } - - - static void LoadMainDicomTags(std::map& target, - ResourceType level) - { - const MainDicomTag* tags = NULL; - size_t size; - LoadMainDicomTags(tags, size, level); - - assert(tags != NULL && - size != 0); - - for (size_t i = 0; i < size; i++) - { - assert(target.find(tags[i].name_) == target.end()); - - target[tags[i].name_] = tags[i].tag_; - } - } - - - void DicomMap::SetValueInternal(uint16_t group, - uint16_t element, - DicomValue* value) - { - DicomTag tag(group, element); - Content::iterator it = content_.find(tag); - - if (it != content_.end()) - { - delete it->second; - it->second = value; - } - else - { - content_.insert(std::make_pair(tag, value)); - } - } - - - void DicomMap::Clear() - { - for (Content::iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(it->second != NULL); - delete it->second; - } - - content_.clear(); - } - - - static void ExtractTags(DicomMap& result, - const DicomMap::Content& source, - const MainDicomTag* tags, - size_t count) - { - result.Clear(); - - for (unsigned int i = 0; i < count; i++) - { - DicomMap::Content::const_iterator it = source.find(tags[i].tag_); - if (it != source.end()) - { - result.SetValue(it->first, *it->second /* value will be cloned */); - } - } - } - - - void DicomMap::ExtractPatientInformation(DicomMap& result) const - { - ExtractTags(result, content_, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - } - - void DicomMap::ExtractStudyInformation(DicomMap& result) const - { - ExtractTags(result, content_, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - } - - void DicomMap::ExtractSeriesInformation(DicomMap& result) const - { - ExtractTags(result, content_, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - } - - void DicomMap::ExtractInstanceInformation(DicomMap& result) const - { - ExtractTags(result, content_, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - } - - - - DicomMap* DicomMap::Clone() const - { - std::unique_ptr result(new DicomMap); - - for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) - { - result->content_.insert(std::make_pair(it->first, it->second->Clone())); - } - - return result.release(); - } - - - void DicomMap::Assign(const DicomMap& other) - { - Clear(); - - for (Content::const_iterator it = other.content_.begin(); it != other.content_.end(); ++it) - { - content_.insert(std::make_pair(it->first, it->second->Clone())); - } - } - - - const DicomValue& DicomMap::GetValue(const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value) - { - return *value; - } - else - { - throw OrthancException(ErrorCode_InexistentTag); - } - } - - - const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const - { - Content::const_iterator it = content_.find(tag); - - if (it == content_.end()) - { - return NULL; - } - else - { - return it->second; - } - } - - - void DicomMap::Remove(const DicomTag& tag) - { - Content::iterator it = content_.find(tag); - if (it != content_.end()) - { - delete it->second; - content_.erase(it); - } - } - - - static void SetupFindTemplate(DicomMap& result, - const MainDicomTag* tags, - size_t count) - { - result.Clear(); - - for (size_t i = 0; i < count; i++) - { - result.SetValue(tags[i].tag_, "", false); - } - } - - void DicomMap::SetupFindPatientTemplate(DicomMap& result) - { - SetupFindTemplate(result, PATIENT_MAIN_DICOM_TAGS, sizeof(PATIENT_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - } - - void DicomMap::SetupFindStudyTemplate(DicomMap& result) - { - SetupFindTemplate(result, STUDY_MAIN_DICOM_TAGS, sizeof(STUDY_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); - result.SetValue(DICOM_TAG_PATIENT_ID, "", false); - - // These main DICOM tags are only indirectly related to the - // General Study Module, remove them - result.Remove(DICOM_TAG_INSTITUTION_NAME); - result.Remove(DICOM_TAG_REQUESTING_PHYSICIAN); - result.Remove(DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION); - } - - void DicomMap::SetupFindSeriesTemplate(DicomMap& result) - { - SetupFindTemplate(result, SERIES_MAIN_DICOM_TAGS, sizeof(SERIES_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); - result.SetValue(DICOM_TAG_PATIENT_ID, "", false); - result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); - - // These tags are considered as "main" by Orthanc, but are not in the Series module - result.Remove(DicomTag(0x0008, 0x0070)); // Manufacturer - result.Remove(DicomTag(0x0008, 0x1010)); // Station name - result.Remove(DicomTag(0x0018, 0x0024)); // Sequence name - result.Remove(DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES); - result.Remove(DICOM_TAG_IMAGES_IN_ACQUISITION); - result.Remove(DICOM_TAG_NUMBER_OF_SLICES); - result.Remove(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS); - result.Remove(DICOM_TAG_NUMBER_OF_TIME_SLICES); - result.Remove(DICOM_TAG_IMAGE_ORIENTATION_PATIENT); - result.Remove(DICOM_TAG_SERIES_TYPE); - result.Remove(DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION); - result.Remove(DICOM_TAG_CONTRAST_BOLUS_AGENT); - } - - void DicomMap::SetupFindInstanceTemplate(DicomMap& result) - { - SetupFindTemplate(result, INSTANCE_MAIN_DICOM_TAGS, sizeof(INSTANCE_MAIN_DICOM_TAGS) / sizeof(MainDicomTag)); - result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); - result.SetValue(DICOM_TAG_PATIENT_ID, "", false); - result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); - result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false); - } - - - void DicomMap::CopyTagIfExists(const DicomMap& source, - const DicomTag& tag) - { - if (source.HasTag(tag)) - { - SetValue(tag, source.GetValue(tag)); - } - } - - - bool DicomMap::IsMainDicomTag(const DicomTag& tag, ResourceType level) - { - const MainDicomTag *tags = NULL; - size_t size; - LoadMainDicomTags(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (tags[i].tag_ == tag) - { - return true; - } - } - - return false; - } - - bool DicomMap::IsMainDicomTag(const DicomTag& tag) - { - return (IsMainDicomTag(tag, ResourceType_Patient) || - IsMainDicomTag(tag, ResourceType_Study) || - IsMainDicomTag(tag, ResourceType_Series) || - IsMainDicomTag(tag, ResourceType_Instance)); - } - - - void DicomMap::GetMainDicomTagsInternal(std::set& result, ResourceType level) - { - const MainDicomTag *tags = NULL; - size_t size; - LoadMainDicomTags(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - result.insert(tags[i].tag_); - } - } - - - void DicomMap::GetMainDicomTags(std::set& result, ResourceType level) - { - result.clear(); - GetMainDicomTagsInternal(result, level); - } - - - void DicomMap::GetMainDicomTags(std::set& result) - { - result.clear(); - GetMainDicomTagsInternal(result, ResourceType_Patient); - GetMainDicomTagsInternal(result, ResourceType_Study); - GetMainDicomTagsInternal(result, ResourceType_Series); - GetMainDicomTagsInternal(result, ResourceType_Instance); - } - - - void DicomMap::GetTags(std::set& tags) const - { - tags.clear(); - - for (Content::const_iterator it = content_.begin(); - it != content_.end(); ++it) - { - tags.insert(it->first); - } - } - - - static uint16_t ReadUnsignedInteger16(const char* dicom) - { - return le16toh(*reinterpret_cast(dicom)); - } - - - static uint32_t ReadUnsignedInteger32(const char* dicom) - { - return le32toh(*reinterpret_cast(dicom)); - } - - - static bool ValidateTag(const ValueRepresentation& vr, - const std::string& value) - { - switch (vr) - { - case ValueRepresentation_ApplicationEntity: - return value.size() <= 16; - - case ValueRepresentation_AgeString: - return (value.size() == 4 && - isdigit(value[0]) && - isdigit(value[1]) && - isdigit(value[2]) && - (value[3] == 'D' || value[3] == 'W' || value[3] == 'M' || value[3] == 'Y')); - - case ValueRepresentation_AttributeTag: - return value.size() == 4; - - case ValueRepresentation_CodeString: - return value.size() <= 16; - - case ValueRepresentation_Date: - return value.size() <= 18; - - case ValueRepresentation_DecimalString: - return value.size() <= 16; - - case ValueRepresentation_DateTime: - return value.size() <= 54; - - case ValueRepresentation_FloatingPointSingle: - return value.size() == 4; - - case ValueRepresentation_FloatingPointDouble: - return value.size() == 8; - - case ValueRepresentation_IntegerString: - return value.size() <= 12; - - case ValueRepresentation_LongString: - return value.size() <= 64; - - case ValueRepresentation_LongText: - return value.size() <= 10240; - - case ValueRepresentation_OtherByte: - return true; - - case ValueRepresentation_OtherDouble: - return value.size() <= (static_cast(1) << 32) - 8; - - case ValueRepresentation_OtherFloat: - return value.size() <= (static_cast(1) << 32) - 4; - - case ValueRepresentation_OtherLong: - return true; - - case ValueRepresentation_OtherWord: - return true; - - case ValueRepresentation_PersonName: - return true; - - case ValueRepresentation_ShortString: - return value.size() <= 16; - - case ValueRepresentation_SignedLong: - return value.size() == 4; - - case ValueRepresentation_Sequence: - return true; - - case ValueRepresentation_SignedShort: - return value.size() == 2; - - case ValueRepresentation_ShortText: - return value.size() <= 1024; - - case ValueRepresentation_Time: - return value.size() <= 28; - - case ValueRepresentation_UnlimitedCharacters: - return value.size() <= (static_cast(1) << 32) - 2; - - case ValueRepresentation_UniqueIdentifier: - return value.size() <= 64; - - case ValueRepresentation_UnsignedLong: - return value.size() == 4; - - case ValueRepresentation_Unknown: - return true; - - case ValueRepresentation_UniversalResource: - return value.size() <= (static_cast(1) << 32) - 2; - - case ValueRepresentation_UnsignedShort: - return value.size() == 2; - - case ValueRepresentation_UnlimitedText: - return value.size() <= (static_cast(1) << 32) - 2; - - default: - // Assume unsupported tags are OK - return true; - } - } - - - static void RemoveTagPadding(std::string& value, - const ValueRepresentation& vr) - { - /** - * Remove padding from character strings, if need be. For the time - * being, only the UI VR is supported. - * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html - **/ - - switch (vr) - { - case ValueRepresentation_UniqueIdentifier: - { - /** - * "Values with a VR of UI shall be padded with a single - * trailing NULL (00H) character when necessary to achieve even - * length." - **/ - - if (!value.empty() && - value[value.size() - 1] == '\0') - { - value.resize(value.size() - 1); - } - - break; - } - - /** - * TODO implement other VR - **/ - - default: - // No padding is applicable to this VR - break; - } - } - - - static bool ReadNextTag(DicomTag& tag, - ValueRepresentation& vr, - std::string& value, - const char* dicom, - size_t size, - size_t& position) - { - /** - * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_7.html#sect_7.1.2 - * This function reads a data element with Explicit VR encoded using Little-Endian. - **/ - - if (position + 6 > size) - { - return false; - } - - tag = DicomTag(ReadUnsignedInteger16(dicom + position), - ReadUnsignedInteger16(dicom + position + 2)); - - vr = StringToValueRepresentation(std::string(dicom + position + 4, 2), true); - if (vr == ValueRepresentation_NotSupported) - { - return false; - } - - if (vr == ValueRepresentation_OtherByte || - vr == ValueRepresentation_OtherDouble || - vr == ValueRepresentation_OtherFloat || - vr == ValueRepresentation_OtherLong || - vr == ValueRepresentation_OtherWord || - vr == ValueRepresentation_Sequence || - vr == ValueRepresentation_UnlimitedCharacters || - vr == ValueRepresentation_UniversalResource || - vr == ValueRepresentation_UnlimitedText || - vr == ValueRepresentation_Unknown) // Note that "UN" should never appear in the Meta Information - { - if (position + 12 > size) - { - return false; - } - - uint32_t length = ReadUnsignedInteger32(dicom + position + 8); - - if (position + 12 + length > size) - { - return false; - } - - value.assign(dicom + position + 12, length); - position += (12 + length); - } - else - { - if (position + 8 > size) - { - return false; - } - - uint16_t length = ReadUnsignedInteger16(dicom + position + 6); - - if (position + 8 + length > size) - { - return false; - } - - value.assign(dicom + position + 8, length); - position += (8 + length); - } - - if (!ValidateTag(vr, value)) - { - return false; - } - - RemoveTagPadding(value, vr); - - return true; - } - - - bool DicomMap::IsDicomFile(const void* dicom, - size_t size) - { - /** - * http://dicom.nema.org/medical/dicom/current/output/chtml/part10/chapter_7.html - * According to Table 7.1-1, besides the "DICM" DICOM prefix, the - * file preamble (i.e. dicom[0..127]) should not be taken into - * account to determine whether the file is or is not a DICOM file. - **/ - - const uint8_t* p = reinterpret_cast(dicom); - - return (size >= 132 && - p[128] == 'D' && - p[129] == 'I' && - p[130] == 'C' && - p[131] == 'M'); - } - - - bool DicomMap::ParseDicomMetaInformation(DicomMap& result, - const void* dicom, - size_t size) - { - if (!IsDicomFile(dicom, size)) - { - return false; - } - - - /** - * The DICOM File Meta Information must be encoded using the - * Explicit VR Little Endian Transfer Syntax - * (UID=1.2.840.10008.1.2.1). - **/ - - result.Clear(); - - // First, we read the "File Meta Information Group Length" tag - // (0002,0000) to know where to stop reading the meta header - size_t position = 132; - - DicomTag tag(0x0000, 0x0000); // Dummy initialization - ValueRepresentation vr; - std::string value; - if (!ReadNextTag(tag, vr, value, reinterpret_cast(dicom), size, position) || - tag.GetGroup() != 0x0002 || - tag.GetElement() != 0x0000 || - vr != ValueRepresentation_UnsignedLong || - value.size() != 4) - { - return false; - } - - size_t stopPosition = position + ReadUnsignedInteger32(value.c_str()); - if (stopPosition > size) - { - return false; - } - - while (position < stopPosition) - { - if (ReadNextTag(tag, vr, value, reinterpret_cast(dicom), size, position)) - { - result.SetValue(tag, value, IsBinaryValueRepresentation(vr)); - } - else - { - return false; - } - } - - return true; - } - - - static std::string ValueAsString(const DicomMap& summary, - const DicomTag& tag) - { - const DicomValue& value = summary.GetValue(tag); - if (value.IsNull()) - { - return "(null)"; - } - else - { - return value.GetContent(); - } - } - - - void DicomMap::LogMissingTagsForStore() const - { - std::string s, t; - - if (HasTag(DICOM_TAG_PATIENT_ID)) - { - if (t.size() > 0) - t += ", "; - t += "PatientID=" + ValueAsString(*this, DICOM_TAG_PATIENT_ID); - } - else - { - if (s.size() > 0) - s += ", "; - s += "PatientID"; - } - - if (HasTag(DICOM_TAG_STUDY_INSTANCE_UID)) - { - if (t.size() > 0) - t += ", "; - t += "StudyInstanceUID=" + ValueAsString(*this, DICOM_TAG_STUDY_INSTANCE_UID); - } - else - { - if (s.size() > 0) - s += ", "; - s += "StudyInstanceUID"; - } - - if (HasTag(DICOM_TAG_SERIES_INSTANCE_UID)) - { - if (t.size() > 0) - t += ", "; - t += "SeriesInstanceUID=" + ValueAsString(*this, DICOM_TAG_SERIES_INSTANCE_UID); - } - else - { - if (s.size() > 0) - s += ", "; - s += "SeriesInstanceUID"; - } - - if (HasTag(DICOM_TAG_SOP_INSTANCE_UID)) - { - if (t.size() > 0) - t += ", "; - t += "SOPInstanceUID=" + ValueAsString(*this, DICOM_TAG_SOP_INSTANCE_UID); - } - else - { - if (s.size() > 0) - s += ", "; - s += "SOPInstanceUID"; - } - - if (t.size() == 0) - { - LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)"; - } - else - { - LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t; - } - } - - - bool DicomMap::LookupStringValue(std::string& result, - const DicomTag& tag, - bool allowBinary) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->CopyToString(result, allowBinary); - } - } - - bool DicomMap::ParseInteger32(int32_t& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseInteger32(result); - } - } - - bool DicomMap::ParseInteger64(int64_t& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseInteger64(result); - } - } - - bool DicomMap::ParseUnsignedInteger32(uint32_t& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseUnsignedInteger32(result); - } - } - - bool DicomMap::ParseUnsignedInteger64(uint64_t& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseUnsignedInteger64(result); - } - } - - bool DicomMap::ParseFloat(float& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseFloat(result); - } - } - - bool DicomMap::ParseFirstFloat(float& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseFirstFloat(result); - } - } - - bool DicomMap::ParseDouble(double& result, - const DicomTag& tag) const - { - const DicomValue* value = TestAndGetValue(tag); - - if (value == NULL) - { - return false; - } - else - { - return value->ParseDouble(result); - } - } - - - void DicomMap::FromDicomAsJson(const Json::Value& dicomAsJson) - { - if (dicomAsJson.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Clear(); - - Json::Value::Members tags = dicomAsJson.getMemberNames(); - for (Json::Value::Members::const_iterator - it = tags.begin(); it != tags.end(); ++it) - { - DicomTag tag(0, 0); - if (!DicomTag::ParseHexadecimal(tag, it->c_str())) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - - const Json::Value& value = dicomAsJson[*it]; - - if (value.type() != Json::objectValue || - !value.isMember("Type") || - !value.isMember("Value") || - value["Type"].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - - if (value["Type"] == "String") - { - if (value["Value"].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - else - { - SetValue(tag, value["Value"].asString(), false /* not binary */); - } - } - } - } - - - void DicomMap::Merge(const DicomMap& other) - { - for (Content::const_iterator it = other.content_.begin(); - it != other.content_.end(); ++it) - { - assert(it->second != NULL); - - if (content_.find(it->first) == content_.end()) - { - content_[it->first] = it->second->Clone(); - } - } - } - - - void DicomMap::MergeMainDicomTags(const DicomMap& other, - ResourceType level) - { - const MainDicomTag* tags = NULL; - size_t size = 0; - - LoadMainDicomTags(tags, size, level); - assert(tags != NULL && size > 0); - - for (size_t i = 0; i < size; i++) - { - Content::const_iterator found = other.content_.find(tags[i].tag_); - - if (found != other.content_.end() && - content_.find(tags[i].tag_) == content_.end()) - { - assert(found->second != NULL); - content_[tags[i].tag_] = found->second->Clone(); - } - } - } - - - void DicomMap::ExtractMainDicomTags(const DicomMap& other) - { - Clear(); - MergeMainDicomTags(other, ResourceType_Patient); - MergeMainDicomTags(other, ResourceType_Study); - MergeMainDicomTags(other, ResourceType_Series); - MergeMainDicomTags(other, ResourceType_Instance); - } - - - bool DicomMap::HasOnlyMainDicomTags() const - { - // TODO - Speed up possible by making this std::set a global variable - - std::set mainDicomTags; - GetMainDicomTags(mainDicomTags); - - for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) - { - if (mainDicomTags.find(it->first) == mainDicomTags.end()) - { - return false; - } - } - - return true; - } - - - void DicomMap::Serialize(Json::Value& target) const - { - target = Json::objectValue; - - for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(it->second != NULL); - - std::string tag = it->first.Format(); - - Json::Value value; - it->second->Serialize(value); - - target[tag] = value; - } - } - - - void DicomMap::Unserialize(const Json::Value& source) - { - Clear(); - - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value::Members tags = source.getMemberNames(); - - for (size_t i = 0; i < tags.size(); i++) - { - DicomTag tag(0, 0); - - if (!DicomTag::ParseHexadecimal(tag, tags[i].c_str()) || - content_.find(tag) != content_.end()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - std::unique_ptr value(new DicomValue); - value->Unserialize(source[tags[i]]); - - content_[tag] = value.release(); - } - } - - - void DicomMap::FromDicomWeb(const Json::Value& source) - { - static const char* const ALPHABETIC = "Alphabetic"; - static const char* const IDEOGRAPHIC = "Ideographic"; - static const char* const INLINE_BINARY = "InlineBinary"; - static const char* const PHONETIC = "Phonetic"; - static const char* const VALUE = "Value"; - static const char* const VR = "vr"; - - Clear(); - - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value::Members tags = source.getMemberNames(); - - for (size_t i = 0; i < tags.size(); i++) - { - const Json::Value& item = source[tags[i]]; - DicomTag tag(0, 0); - - if (item.type() != Json::objectValue || - !item.isMember(VR) || - item[VR].type() != Json::stringValue || - !DicomTag::ParseHexadecimal(tag, tags[i].c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - ValueRepresentation vr = StringToValueRepresentation(item[VR].asString(), false); - - if (item.isMember(INLINE_BINARY)) - { - const Json::Value& value = item[INLINE_BINARY]; - - if (value.type() == Json::stringValue) - { - std::string decoded; - Toolbox::DecodeBase64(decoded, value.asString()); - SetValue(tag, decoded, true /* binary data */); - } - } - else if (!item.isMember(VALUE)) - { - // Tag is present, but it has a null value - SetValue(tag, "", false /* not binary */); - } - else - { - const Json::Value& value = item[VALUE]; - - if (value.type() == Json::arrayValue) - { - bool supported = true; - - std::string s; - for (Json::Value::ArrayIndex i = 0; i < value.size() && supported; i++) - { - if (!s.empty()) - { - s += '\\'; - } - - switch (value[i].type()) - { - case Json::objectValue: - if (vr == ValueRepresentation_PersonName && - value[i].type() == Json::objectValue) - { - if (value[i].isMember(ALPHABETIC) && - value[i][ALPHABETIC].type() == Json::stringValue) - { - s += value[i][ALPHABETIC].asString(); - } - - bool hasIdeographic = false; - - if (value[i].isMember(IDEOGRAPHIC) && - value[i][IDEOGRAPHIC].type() == Json::stringValue) - { - s += '=' + value[i][IDEOGRAPHIC].asString(); - hasIdeographic = true; - } - - if (value[i].isMember(PHONETIC) && - value[i][PHONETIC].type() == Json::stringValue) - { - if (!hasIdeographic) - { - s += '='; - } - - s += '=' + value[i][PHONETIC].asString(); - } - } - else - { - // This is the case of sequences - supported = false; - } - - break; - - case Json::stringValue: - s += value[i].asString(); - break; - - case Json::intValue: - s += boost::lexical_cast(value[i].asInt()); - break; - - case Json::uintValue: - s += boost::lexical_cast(value[i].asUInt()); - break; - - case Json::realValue: - s += boost::lexical_cast(value[i].asDouble()); - break; - - default: - break; - } - } - - if (supported) - { - SetValue(tag, s, false /* not binary */); - } - } - } - } - } - - - std::string DicomMap::GetStringValue(const DicomTag& tag, - const std::string& defaultValue, - bool allowBinary) const - { - std::string s; - if (LookupStringValue(s, tag, allowBinary)) - { - return s; - } - else - { - return defaultValue; - } - } - - - void DicomMap::RemoveBinaryTags() - { - Content kept; - - for (Content::iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(it->second != NULL); - - if (!it->second->IsBinary() && - !it->second->IsNull()) - { - kept[it->first] = it->second; - } - else - { - delete it->second; - } - } - - content_ = kept; - } - - - void DicomMap::DumpMainDicomTags(Json::Value& target, - ResourceType level) const - { - std::map mainTags; // TODO - Create a singleton to hold this map - LoadMainDicomTags(mainTags, level); - - target = Json::objectValue; - - for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(it->second != NULL); - - if (!it->second->IsBinary() && - !it->second->IsNull()) - { - std::map::const_iterator found = mainTags.find(it->first); - - if (found != mainTags.end()) - { - target[found->second] = it->second->GetContent(); - } - } - } - } - - - void DicomMap::ParseMainDicomTags(const Json::Value& source, - ResourceType level) - { - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - std::map mainTags; // TODO - Create a singleton to hold this map - LoadMainDicomTags(mainTags, level); - - Json::Value::Members members = source.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - std::map::const_iterator found = mainTags.find(members[i]); - - if (found != mainTags.end()) - { - const Json::Value& value = source[members[i]]; - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - SetValue(found->second, value.asString(), false); - } - } - } - } - - - void DicomMap::Print(FILE* fp) const - { - DicomArray a(*this); - a.Print(fp); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomMap.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,248 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomTag.h" -#include "DicomValue.h" -#include "../Enumerations.h" - -#include -#include -#include - -namespace Orthanc -{ - class DicomMap : public boost::noncopyable - { - public: - typedef std::map Content; - - private: - friend class DicomArray; - friend class FromDcmtkBridge; - friend class ParsedDicomFile; - - Content content_; - - // Warning: This takes the ownership of "value" - void SetValueInternal(uint16_t group, - uint16_t element, - DicomValue* value); - - static void GetMainDicomTagsInternal(std::set& result, - ResourceType level); - - public: - DicomMap() - { - } - - ~DicomMap() - { - Clear(); - } - - size_t GetSize() const - { - return content_.size(); - } - - DicomMap* Clone() const; - - void Assign(const DicomMap& other); - - void Clear(); - - void SetNullValue(uint16_t group, - uint16_t element) - { - SetValueInternal(group, element, new DicomValue); - } - - void SetNullValue(const DicomTag& tag) - { - SetValueInternal(tag.GetGroup(), tag.GetElement(), new DicomValue); - } - - void SetValue(uint16_t group, - uint16_t element, - const DicomValue& value) - { - SetValueInternal(group, element, value.Clone()); - } - - void SetValue(const DicomTag& tag, - const DicomValue& value) - { - SetValueInternal(tag.GetGroup(), tag.GetElement(), value.Clone()); - } - - void SetValue(const DicomTag& tag, - const std::string& str, - bool isBinary) - { - SetValueInternal(tag.GetGroup(), tag.GetElement(), new DicomValue(str, isBinary)); - } - - void SetValue(uint16_t group, - uint16_t element, - const std::string& str, - bool isBinary) - { - SetValueInternal(group, element, new DicomValue(str, isBinary)); - } - - bool HasTag(uint16_t group, uint16_t element) const - { - return HasTag(DicomTag(group, element)); - } - - bool HasTag(const DicomTag& tag) const - { - return content_.find(tag) != content_.end(); - } - - const DicomValue& GetValue(uint16_t group, uint16_t element) const - { - return GetValue(DicomTag(group, element)); - } - - const DicomValue& GetValue(const DicomTag& tag) const; - - // DO NOT delete the returned value! - const DicomValue* TestAndGetValue(uint16_t group, uint16_t element) const - { - return TestAndGetValue(DicomTag(group, element)); - } - - // DO NOT delete the returned value! - const DicomValue* TestAndGetValue(const DicomTag& tag) const; - - void Remove(const DicomTag& tag); - - void ExtractPatientInformation(DicomMap& result) const; - - void ExtractStudyInformation(DicomMap& result) const; - - void ExtractSeriesInformation(DicomMap& result) const; - - void ExtractInstanceInformation(DicomMap& result) const; - - static void SetupFindPatientTemplate(DicomMap& result); - - static void SetupFindStudyTemplate(DicomMap& result); - - static void SetupFindSeriesTemplate(DicomMap& result); - - static void SetupFindInstanceTemplate(DicomMap& result); - - void CopyTagIfExists(const DicomMap& source, - const DicomTag& tag); - - static bool IsMainDicomTag(const DicomTag& tag, ResourceType level); - - static bool IsMainDicomTag(const DicomTag& tag); - - static void GetMainDicomTags(std::set& result, ResourceType level); - - static void GetMainDicomTags(std::set& result); - - void GetTags(std::set& tags) const; - - static bool IsDicomFile(const void* dicom, - size_t size); - - static bool ParseDicomMetaInformation(DicomMap& result, - const void* dicom, - size_t size); - - void LogMissingTagsForStore() const; - - bool LookupStringValue(std::string& result, - const DicomTag& tag, - bool allowBinary) const; - - bool ParseInteger32(int32_t& result, - const DicomTag& tag) const; - - bool ParseInteger64(int64_t& result, - const DicomTag& tag) const; - - bool ParseUnsignedInteger32(uint32_t& result, - const DicomTag& tag) const; - - bool ParseUnsignedInteger64(uint64_t& result, - const DicomTag& tag) const; - - bool ParseFloat(float& result, - const DicomTag& tag) const; - - bool ParseFirstFloat(float& result, - const DicomTag& tag) const; - - bool ParseDouble(double& result, - const DicomTag& tag) const; - - void FromDicomAsJson(const Json::Value& dicomAsJson); - - void Merge(const DicomMap& other); - - void MergeMainDicomTags(const DicomMap& other, - ResourceType level); - - void ExtractMainDicomTags(const DicomMap& other); - - bool HasOnlyMainDicomTags() const; - - void Serialize(Json::Value& target) const; - - void Unserialize(const Json::Value& source); - - void FromDicomWeb(const Json::Value& source); - - std::string GetStringValue(const DicomTag& tag, - const std::string& defaultValue, - bool allowBinary) const; - - void RemoveBinaryTags(); - - void DumpMainDicomTags(Json::Value& target, - ResourceType level) const; - - void ParseMainDicomTags(const Json::Value& source, - ResourceType level); - - void Print(FILE* fp) const; // For debugging only - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,323 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomTag.h" - -#include "../OrthancException.h" - -#include -#include -#include -#include - -namespace Orthanc -{ - static inline uint16_t GetCharValue(char c) - { - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else - return 0; - } - - - static inline uint16_t GetTagValue(const char* c) - { - return ((GetCharValue(c[0]) << 12) + - (GetCharValue(c[1]) << 8) + - (GetCharValue(c[2]) << 4) + - GetCharValue(c[3])); - } - - - bool DicomTag::operator< (const DicomTag& other) const - { - if (group_ < other.group_) - return true; - - if (group_ > other.group_) - return false; - - return element_ < other.element_; - } - - - std::ostream& operator<< (std::ostream& o, const DicomTag& tag) - { - using namespace std; - ios_base::fmtflags state = o.flags(); - o.flags(ios::right | ios::hex); - o << "(" << setfill('0') << setw(4) << tag.GetGroup() - << "," << setw(4) << tag.GetElement() << ")"; - o.flags(state); - return o; - } - - - std::string DicomTag::Format() const - { - char b[16]; - sprintf(b, "%04x,%04x", group_, element_); - return std::string(b); - } - - - bool DicomTag::ParseHexadecimal(DicomTag& tag, - const char* value) - { - size_t length = strlen(value); - - if (length == 9 && - isxdigit(value[0]) && - isxdigit(value[1]) && - isxdigit(value[2]) && - isxdigit(value[3]) && - (value[4] == '-' || value[4] == ',') && - isxdigit(value[5]) && - isxdigit(value[6]) && - isxdigit(value[7]) && - isxdigit(value[8])) - { - uint16_t group = GetTagValue(value); - uint16_t element = GetTagValue(value + 5); - tag = DicomTag(group, element); - return true; - } - else if (length == 8 && - isxdigit(value[0]) && - isxdigit(value[1]) && - isxdigit(value[2]) && - isxdigit(value[3]) && - isxdigit(value[4]) && - isxdigit(value[5]) && - isxdigit(value[6]) && - isxdigit(value[7])) - { - uint16_t group = GetTagValue(value); - uint16_t element = GetTagValue(value + 4); - tag = DicomTag(group, element); - return true; - } - else - { - return false; - } - } - - - const char* DicomTag::GetMainTagsName() const - { - if (*this == DICOM_TAG_ACCESSION_NUMBER) - return "AccessionNumber"; - - if (*this == DICOM_TAG_SOP_INSTANCE_UID) - return "SOPInstanceUID"; - - if (*this == DICOM_TAG_PATIENT_ID) - return "PatientID"; - - if (*this == DICOM_TAG_SERIES_INSTANCE_UID) - return "SeriesInstanceUID"; - - if (*this == DICOM_TAG_STUDY_INSTANCE_UID) - return "StudyInstanceUID"; - - if (*this == DICOM_TAG_PIXEL_DATA) - return "PixelData"; - - if (*this == DICOM_TAG_IMAGE_INDEX) - return "ImageIndex"; - - if (*this == DICOM_TAG_INSTANCE_NUMBER) - return "InstanceNumber"; - - if (*this == DICOM_TAG_NUMBER_OF_SLICES) - return "NumberOfSlices"; - - if (*this == DICOM_TAG_NUMBER_OF_FRAMES) - return "NumberOfFrames"; - - if (*this == DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES) - return "CardiacNumberOfImages"; - - if (*this == DICOM_TAG_IMAGES_IN_ACQUISITION) - return "ImagesInAcquisition"; - - if (*this == DICOM_TAG_PATIENT_NAME) - return "PatientName"; - - if (*this == DICOM_TAG_IMAGE_POSITION_PATIENT) - return "ImagePositionPatient"; - - if (*this == DICOM_TAG_IMAGE_ORIENTATION_PATIENT) - return "ImageOrientationPatient"; - - // New in Orthanc 1.6.0, as tagged as "RETIRED_" since DCMTK 3.6.4 - if (*this == DICOM_TAG_OTHER_PATIENT_IDS) - return "OtherPatientIDs"; - - return ""; - } - - - void DicomTag::AddTagsForModule(std::set& target, - DicomModule module) - { - // REFERENCE: 11_03pu.pdf, DICOM PS 3.3 2011 - Information Object Definitions - - switch (module) - { - case DicomModule_Patient: - // This is Table C.7-1 "Patient Module Attributes" (p. 373) - target.insert(DicomTag(0x0010, 0x0010)); // Patient's name - target.insert(DicomTag(0x0010, 0x0020)); // Patient ID - target.insert(DicomTag(0x0010, 0x0030)); // Patient's birth date - target.insert(DicomTag(0x0010, 0x0040)); // Patient's sex - target.insert(DicomTag(0x0008, 0x1120)); // Referenced patient sequence - target.insert(DicomTag(0x0010, 0x0032)); // Patient's birth time - target.insert(DicomTag(0x0010, 0x1000)); // Other patient IDs - target.insert(DicomTag(0x0010, 0x1002)); // Other patient IDs sequence - target.insert(DicomTag(0x0010, 0x1001)); // Other patient names - target.insert(DicomTag(0x0010, 0x2160)); // Ethnic group - target.insert(DicomTag(0x0010, 0x4000)); // Patient comments - target.insert(DicomTag(0x0010, 0x2201)); // Patient species description - target.insert(DicomTag(0x0010, 0x2202)); // Patient species code sequence - target.insert(DicomTag(0x0010, 0x2292)); // Patient breed description - target.insert(DicomTag(0x0010, 0x2293)); // Patient breed code sequence - target.insert(DicomTag(0x0010, 0x2294)); // Breed registration sequence - target.insert(DicomTag(0x0010, 0x2297)); // Responsible person - target.insert(DicomTag(0x0010, 0x2298)); // Responsible person role - target.insert(DicomTag(0x0010, 0x2299)); // Responsible organization - target.insert(DicomTag(0x0012, 0x0062)); // Patient identity removed - target.insert(DicomTag(0x0012, 0x0063)); // De-identification method - target.insert(DicomTag(0x0012, 0x0064)); // De-identification method code sequence - - // Table 10-18 ISSUER OF PATIENT ID MACRO (p. 112) - target.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID - target.insert(DicomTag(0x0010, 0x0024)); // Issuer of Patient ID qualifiers sequence - break; - - case DicomModule_Study: - // This is Table C.7-3 "General Study Module Attributes" (p. 378) - target.insert(DicomTag(0x0020, 0x000d)); // Study instance UID - target.insert(DicomTag(0x0008, 0x0020)); // Study date - target.insert(DicomTag(0x0008, 0x0030)); // Study time - target.insert(DicomTag(0x0008, 0x0090)); // Referring physician's name - target.insert(DicomTag(0x0008, 0x0096)); // Referring physician identification sequence - target.insert(DicomTag(0x0020, 0x0010)); // Study ID - target.insert(DicomTag(0x0008, 0x0050)); // Accession number - target.insert(DicomTag(0x0008, 0x0051)); // Issuer of accession number sequence - target.insert(DicomTag(0x0008, 0x1030)); // Study description - target.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of record - target.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of record identification sequence - target.insert(DicomTag(0x0008, 0x1060)); // Name of physician(s) reading study - target.insert(DicomTag(0x0008, 0x1062)); // Physician(s) reading study identification sequence - target.insert(DicomTag(0x0032, 0x1034)); // Requesting service code sequence - target.insert(DicomTag(0x0008, 0x1110)); // Referenced study sequence - target.insert(DicomTag(0x0008, 0x1032)); // Procedure code sequence - target.insert(DicomTag(0x0040, 0x1012)); // Reason for performed procedure code sequence - break; - - case DicomModule_Series: - // This is Table C.7-5 "General Series Module Attributes" (p. 385) - target.insert(DicomTag(0x0008, 0x0060)); // Modality - target.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID - target.insert(DicomTag(0x0020, 0x0011)); // Series Number - target.insert(DicomTag(0x0020, 0x0060)); // Laterality - target.insert(DicomTag(0x0008, 0x0021)); // Series Date - target.insert(DicomTag(0x0008, 0x0031)); // Series Time - target.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians’ Name - target.insert(DicomTag(0x0008, 0x1052)); // Performing Physician Identification Sequence - target.insert(DicomTag(0x0018, 0x1030)); // Protocol Name - target.insert(DicomTag(0x0008, 0x103e)); // Series Description - target.insert(DicomTag(0x0008, 0x103f)); // Series Description Code Sequence - target.insert(DicomTag(0x0008, 0x1070)); // Operators' Name - target.insert(DicomTag(0x0008, 0x1072)); // Operator Identification Sequence - target.insert(DicomTag(0x0008, 0x1111)); // Referenced Performed Procedure Step Sequence - target.insert(DicomTag(0x0008, 0x1250)); // Related Series Sequence - target.insert(DicomTag(0x0018, 0x0015)); // Body Part Examined - target.insert(DicomTag(0x0018, 0x5100)); // Patient Position - target.insert(DicomTag(0x0028, 0x0108)); // Smallest Pixel Value in Series - target.insert(DicomTag(0x0029, 0x0109)); // Largest Pixel Value in Series - target.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence - target.insert(DicomTag(0x0010, 0x2210)); // Anatomical Orientation Type - - // Table 10-16 PERFORMED PROCEDURE STEP SUMMARY MACRO ATTRIBUTES - target.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID - target.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date - target.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time - target.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description - target.insert(DicomTag(0x0040, 0x0260)); // Performed Protocol Code Sequence - target.insert(DicomTag(0x0040, 0x0280)); // Comments on the Performed Procedure Step - break; - - case DicomModule_Instance: - // This is Table C.12-1 "SOP Common Module Attributes" (p. 1207) - target.insert(DicomTag(0x0008, 0x0016)); // SOP Class UID - target.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID - target.insert(DicomTag(0x0008, 0x0005)); // Specific Character Set - target.insert(DicomTag(0x0008, 0x0012)); // Instance Creation Date - target.insert(DicomTag(0x0008, 0x0013)); // Instance Creation Time - target.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID - target.insert(DicomTag(0x0008, 0x001a)); // Related General SOP Class UID - target.insert(DicomTag(0x0008, 0x001b)); // Original Specialized SOP Class UID - target.insert(DicomTag(0x0008, 0x0110)); // Coding Scheme Identification Sequence - target.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC - target.insert(DicomTag(0x0018, 0xa001)); // Contributing Equipment Sequence - target.insert(DicomTag(0x0020, 0x0013)); // Instance Number - target.insert(DicomTag(0x0100, 0x0410)); // SOP Instance Status - target.insert(DicomTag(0x0100, 0x0420)); // SOP Authorization DateTime - target.insert(DicomTag(0x0100, 0x0424)); // SOP Authorization Comment - target.insert(DicomTag(0x0100, 0x0426)); // Authorization Equipment Certification Number - target.insert(DicomTag(0x0400, 0x0500)); // Encrypted Attributes Sequence - target.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence - target.insert(DicomTag(0x0040, 0xa390)); // HL7 Structured Document Reference Sequence - target.insert(DicomTag(0x0028, 0x0303)); // Longitudinal Temporal Information Modified - - // Table C.12-6 "DIGITAL SIGNATURES MACRO ATTRIBUTES" (p. 1216) - target.insert(DicomTag(0x4ffe, 0x0001)); // MAC Parameters sequence - target.insert(DicomTag(0xfffa, 0xfffa)); // Digital signatures sequence - break; - - // TODO IMAGE MODULE? - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomTag.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,243 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include -#include - -#include "../Enumerations.h" - -namespace Orthanc -{ - class DicomTag - { - // This must stay a POD (plain old data structure) - - private: - uint16_t group_; - uint16_t element_; - - public: - DicomTag(uint16_t group, - uint16_t element) : - group_(group), - element_(element) - { - } - - uint16_t GetGroup() const - { - return group_; - } - - uint16_t GetElement() const - { - return element_; - } - - bool IsPrivate() const - { - return group_ % 2 == 1; - } - - const char* GetMainTagsName() const; - - bool operator< (const DicomTag& other) const; - - bool operator== (const DicomTag& other) const - { - return group_ == other.group_ && element_ == other.element_; - } - - bool operator!= (const DicomTag& other) const - { - return !(*this == other); - } - - std::string Format() const; - - static bool ParseHexadecimal(DicomTag& tag, - const char* value); - - friend std::ostream& operator<< (std::ostream& o, const DicomTag& tag); - - static void AddTagsForModule(std::set& target, - DicomModule module); - }; - - // Aliases for the most useful tags - static const DicomTag DICOM_TAG_ACCESSION_NUMBER(0x0008, 0x0050); - static const DicomTag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018); - static const DicomTag DICOM_TAG_PATIENT_ID(0x0010, 0x0020); - static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e); - static const DicomTag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d); - static const DicomTag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010); - static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010); - - static const DicomTag DICOM_TAG_IMAGE_INDEX(0x0054, 0x1330); - static const DicomTag DICOM_TAG_INSTANCE_NUMBER(0x0020, 0x0013); - - static const DicomTag DICOM_TAG_NUMBER_OF_SLICES(0x0054, 0x0081); - static const DicomTag DICOM_TAG_NUMBER_OF_TIME_SLICES(0x0054, 0x0101); - static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008); - static const DicomTag DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES(0x0018, 0x1090); - static const DicomTag DICOM_TAG_IMAGES_IN_ACQUISITION(0x0020, 0x1002); - static const DicomTag DICOM_TAG_PATIENT_NAME(0x0010, 0x0010); - static const DicomTag DICOM_TAG_ENCAPSULATED_DOCUMENT(0x0042, 0x0011); - - static const DicomTag DICOM_TAG_STUDY_DESCRIPTION(0x0008, 0x1030); - static const DicomTag DICOM_TAG_SERIES_DESCRIPTION(0x0008, 0x103e); - static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060); - - // The following is used for "modify/anonymize" operations - static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016); - static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID(0x0002, 0x0002); - static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID(0x0002, 0x0003); - static const DicomTag DICOM_TAG_DEIDENTIFICATION_METHOD(0x0012, 0x0063); - - // DICOM tags used for fMRI (thanks to Will Ryder) - static const DicomTag DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS(0x0020, 0x0105); - static const DicomTag DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER(0x0020, 0x0100); - - // Tags for C-FIND and C-MOVE - static const DicomTag DICOM_TAG_MESSAGE_ID(0x0000, 0x0110); - static const DicomTag DICOM_TAG_SPECIFIC_CHARACTER_SET(0x0008, 0x0005); - static const DicomTag DICOM_TAG_QUERY_RETRIEVE_LEVEL(0x0008, 0x0052); - static const DicomTag DICOM_TAG_MODALITIES_IN_STUDY(0x0008, 0x0061); - - // Tags for images - static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011); - static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010); - static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002); - static const DicomTag DICOM_TAG_BITS_ALLOCATED(0x0028, 0x0100); - static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101); - static const DicomTag DICOM_TAG_HIGH_BIT(0x0028, 0x0102); - static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103); - static const DicomTag DICOM_TAG_PLANAR_CONFIGURATION(0x0028, 0x0006); - static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004); - static const DicomTag DICOM_TAG_IMAGE_ORIENTATION_PATIENT(0x0020, 0x0037); - static const DicomTag DICOM_TAG_IMAGE_POSITION_PATIENT(0x0020, 0x0032); - static const DicomTag DICOM_TAG_LARGEST_IMAGE_PIXEL_VALUE(0x0028, 0x0107); - static const DicomTag DICOM_TAG_SMALLEST_IMAGE_PIXEL_VALUE(0x0028, 0x0106); - - // Tags related to date and time - static const DicomTag DICOM_TAG_ACQUISITION_DATE(0x0008, 0x0022); - static const DicomTag DICOM_TAG_ACQUISITION_TIME(0x0008, 0x0032); - static const DicomTag DICOM_TAG_CONTENT_DATE(0x0008, 0x0023); - static const DicomTag DICOM_TAG_CONTENT_TIME(0x0008, 0x0033); - static const DicomTag DICOM_TAG_INSTANCE_CREATION_DATE(0x0008, 0x0012); - static const DicomTag DICOM_TAG_INSTANCE_CREATION_TIME(0x0008, 0x0013); - static const DicomTag DICOM_TAG_PATIENT_BIRTH_DATE(0x0010, 0x0030); - static const DicomTag DICOM_TAG_PATIENT_BIRTH_TIME(0x0010, 0x0032); - static const DicomTag DICOM_TAG_SERIES_DATE(0x0008, 0x0021); - static const DicomTag DICOM_TAG_SERIES_TIME(0x0008, 0x0031); - static const DicomTag DICOM_TAG_STUDY_DATE(0x0008, 0x0020); - static const DicomTag DICOM_TAG_STUDY_TIME(0x0008, 0x0030); - - // Various tags - static const DicomTag DICOM_TAG_SERIES_TYPE(0x0054, 0x1000); - static const DicomTag DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION(0x0032, 0x1060); - static const DicomTag DICOM_TAG_INSTITUTION_NAME(0x0008, 0x0080); - static const DicomTag DICOM_TAG_REQUESTING_PHYSICIAN(0x0032, 0x1032); - static const DicomTag DICOM_TAG_REFERRING_PHYSICIAN_NAME(0x0008, 0x0090); - static const DicomTag DICOM_TAG_OPERATOR_NAME(0x0008, 0x1070); - static const DicomTag DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION(0x0040, 0x0254); - static const DicomTag DICOM_TAG_IMAGE_COMMENTS(0x0020, 0x4000); - static const DicomTag DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION(0x0018, 0x1400); - static const DicomTag DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_CODE(0x0018, 0x1401); - static const DicomTag DICOM_TAG_CASSETTE_ORIENTATION(0x0018, 0x1402); - static const DicomTag DICOM_TAG_CASSETTE_SIZE(0x0018, 0x1403); - static const DicomTag DICOM_TAG_CONTRAST_BOLUS_AGENT(0x0018, 0x0010); - static const DicomTag DICOM_TAG_STUDY_ID(0x0020, 0x0010); - static const DicomTag DICOM_TAG_SERIES_NUMBER(0x0020, 0x0011); - static const DicomTag DICOM_TAG_PATIENT_SEX(0x0010, 0x0040); - static const DicomTag DICOM_TAG_LATERALITY(0x0020, 0x0060); - static const DicomTag DICOM_TAG_BODY_PART_EXAMINED(0x0018, 0x0015); - static const DicomTag DICOM_TAG_VIEW_POSITION(0x0018, 0x5101); - static const DicomTag DICOM_TAG_MANUFACTURER(0x0008, 0x0070); - static const DicomTag DICOM_TAG_PATIENT_ORIENTATION(0x0020, 0x0020); - static const DicomTag DICOM_TAG_PATIENT_COMMENTS(0x0010, 0x4000); - static const DicomTag DICOM_TAG_PATIENT_SPECIES_DESCRIPTION(0x0010, 0x2201); - static const DicomTag DICOM_TAG_STUDY_COMMENTS(0x0032, 0x4000); - static const DicomTag DICOM_TAG_OTHER_PATIENT_IDS(0x0010, 0x1000); - - // Tags used within the Stone of Orthanc - static const DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009); - static const DicomTag DICOM_TAG_GRID_FRAME_OFFSET_VECTOR(0x3004, 0x000c); - static const DicomTag DICOM_TAG_PIXEL_SPACING(0x0028, 0x0030); - static const DicomTag DICOM_TAG_RESCALE_INTERCEPT(0x0028, 0x1052); - static const DicomTag DICOM_TAG_RESCALE_SLOPE(0x0028, 0x1053); - static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050); - static const DicomTag DICOM_TAG_WINDOW_CENTER(0x0028, 0x1050); - static const DicomTag DICOM_TAG_WINDOW_WIDTH(0x0028, 0x1051); - static const DicomTag DICOM_TAG_DOSE_GRID_SCALING(0x3004, 0x000e); - static const DicomTag DICOM_TAG_RED_PALETTE_COLOR_LOOKUP_TABLE_DATA(0x0028, 0x1201); - static const DicomTag DICOM_TAG_GREEN_PALETTE_COLOR_LOOKUP_TABLE_DATA(0x0028, 0x1202); - static const DicomTag DICOM_TAG_BLUE_PALETTE_COLOR_LOOKUP_TABLE_DATA(0x0028, 0x1203); - static const DicomTag DICOM_TAG_RED_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR(0x0028, 0x1101); - static const DicomTag DICOM_TAG_GREEN_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR(0x0028, 0x1102); - static const DicomTag DICOM_TAG_BLUE_PALETTE_COLOR_LOOKUP_TABLE_DESCRIPTOR(0x0028, 0x1103); - static const DicomTag DICOM_TAG_CONTOUR_DATA(0x3006, 0x0050); - - // Counting patients, studies and series - // https://www.medicalconnections.co.uk/kb/Counting_Studies_Series_and_Instances - static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES(0x0020, 0x1200); - static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES(0x0020, 0x1202); - static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES(0x0020, 0x1204); - static const DicomTag DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES(0x0020, 0x1206); - static const DicomTag DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES(0x0020, 0x1208); - static const DicomTag DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES(0x0020, 0x1209); - static const DicomTag DICOM_TAG_SOP_CLASSES_IN_STUDY(0x0008, 0x0062); - - // Tags to preserve relationships during anonymization - static const DicomTag DICOM_TAG_REFERENCED_IMAGE_SEQUENCE(0x0008, 0x1140); - static const DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155); - static const DicomTag DICOM_TAG_SOURCE_IMAGE_SEQUENCE(0x0008, 0x2112); - static const DicomTag DICOM_TAG_FRAME_OF_REFERENCE_UID(0x0020, 0x0052); - static const DicomTag DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID(0x3006, 0x0024); - static const DicomTag DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID(0x3006, 0x00c2); - static const DicomTag DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE(0x0040, 0xa375); - static const DicomTag DICOM_TAG_REFERENCED_SERIES_SEQUENCE(0x0008, 0x1115); - static const DicomTag DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE(0x3006, 0x0010); - static const DicomTag DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE(0x3006, 0x0012); - static const DicomTag DICOM_TAG_RT_REFERENCED_SERIES_SEQUENCE(0x3006, 0x0014); - - // Tags for DICOMDIR - static const DicomTag DICOM_TAG_DIRECTORY_RECORD_TYPE(0x0004, 0x1430); - static const DicomTag DICOM_TAG_OFFSET_OF_THE_NEXT_DIRECTORY_RECORD(0x0004, 0x1400); - static const DicomTag DICOM_TAG_OFFSET_OF_REFERENCED_LOWER_LEVEL_DIRECTORY_ENTITY(0x0004, 0x1420); - static const DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID_IN_FILE(0x0004, 0x1511); - static const DicomTag DICOM_TAG_REFERENCED_FILE_ID(0x0004, 0x1500); -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,322 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomValue.h" - -#include "../OrthancException.h" -#include "../SerializationToolbox.h" -#include "../Toolbox.h" - -#include - -namespace Orthanc -{ - DicomValue::DicomValue(const DicomValue& other) : - type_(other.type_), - content_(other.content_) - { - } - - - DicomValue::DicomValue(const std::string& content, - bool isBinary) : - type_(isBinary ? Type_Binary : Type_String), - content_(content) - { - } - - - DicomValue::DicomValue(const char* data, - size_t size, - bool isBinary) : - type_(isBinary ? Type_Binary : Type_String) - { - content_.assign(data, size); - } - - - const std::string& DicomValue::GetContent() const - { - if (type_ == Type_Null) - { - throw OrthancException(ErrorCode_BadParameterType); - } - else - { - return content_; - } - } - - - DicomValue* DicomValue::Clone() const - { - return new DicomValue(*this); - } - - -#if ORTHANC_ENABLE_BASE64 == 1 - void DicomValue::FormatDataUriScheme(std::string& target, - const std::string& mime) const - { - Toolbox::EncodeBase64(target, GetContent()); - target.insert(0, "data:" + mime + ";base64,"); - } -#endif - - // same as ParseValue but in case the value actually contains a sequence, - // it will return the first value - // this has been introduced to support invalid "width/height" DICOM tags in some US - // images where the width is stored as "800\0" ! - template - static bool ParseFirstValue(T& result, - const DicomValue& source) - { - if (source.IsBinary() || - source.IsNull()) - { - return false; - } - - try - { - std::string value = Toolbox::StripSpaces(source.GetContent()); - if (value.empty()) - { - return false; - } - - if (!allowSigned && - value[0] == '-') - { - return false; - } - - if (value.find("\\") == std::string::npos) - { - result = boost::lexical_cast(value); - return true; - } - else - { - std::vector tokens; - Toolbox::TokenizeString(tokens, value, '\\'); - - if (tokens.size() >= 1) - { - result = boost::lexical_cast(tokens[0]); - return true; - } - - return false; - } - } - catch (boost::bad_lexical_cast&) - { - return false; - } - } - - - template - static bool ParseValue(T& result, - const DicomValue& source) - { - if (source.IsBinary() || - source.IsNull()) - { - return false; - } - - try - { - std::string value = Toolbox::StripSpaces(source.GetContent()); - if (value.empty()) - { - return false; - } - - if (!allowSigned && - value[0] == '-') - { - return false; - } - - result = boost::lexical_cast(value); - return true; - } - catch (boost::bad_lexical_cast&) - { - return false; - } - } - - bool DicomValue::ParseInteger32(int32_t& result) const - { - int64_t tmp; - if (ParseValue(tmp, *this)) - { - result = static_cast(tmp); - return (tmp == static_cast(result)); // Check no overflow occurs - } - else - { - return false; - } - } - - bool DicomValue::ParseInteger64(int64_t& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseUnsignedInteger32(uint32_t& result) const - { - uint64_t tmp; - if (ParseValue(tmp, *this)) - { - result = static_cast(tmp); - return (tmp == static_cast(result)); // Check no overflow occurs - } - else - { - return false; - } - } - - bool DicomValue::ParseUnsignedInteger64(uint64_t& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseFloat(float& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseDouble(double& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseFirstFloat(float& result) const - { - return ParseFirstValue(result, *this); - } - - bool DicomValue::ParseFirstUnsignedInteger(unsigned int& result) const - { - return ParseFirstValue(result, *this); - } - - bool DicomValue::CopyToString(std::string& result, - bool allowBinary) const - { - if (IsNull()) - { - return false; - } - else if (IsBinary() && !allowBinary) - { - return false; - } - else - { - result.assign(content_); - return true; - } - } - - - static const char* KEY_TYPE = "Type"; - static const char* KEY_CONTENT = "Content"; - - void DicomValue::Serialize(Json::Value& target) const - { - target = Json::objectValue; - - switch (type_) - { - case Type_Null: - target[KEY_TYPE] = "Null"; - break; - - case Type_String: - target[KEY_TYPE] = "String"; - target[KEY_CONTENT] = content_; - break; - - case Type_Binary: - { - target[KEY_TYPE] = "Binary"; - - std::string base64; - Toolbox::EncodeBase64(base64, content_); - target[KEY_CONTENT] = base64; - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - void DicomValue::Unserialize(const Json::Value& source) - { - std::string type = SerializationToolbox::ReadString(source, KEY_TYPE); - - if (type == "Null") - { - type_ = Type_Null; - content_.clear(); - } - else if (type == "String") - { - type_ = Type_String; - content_ = SerializationToolbox::ReadString(source, KEY_CONTENT); - } - else if (type == "Binary") - { - type_ = Type_Binary; - - const std::string base64 =SerializationToolbox::ReadString(source, KEY_CONTENT); - Toolbox::DecodeBase64(content_, base64); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomFormat/DicomValue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include -#include -#include - -#if !defined(ORTHANC_ENABLE_BASE64) -# error The macro ORTHANC_ENABLE_BASE64 must be defined -#endif - - -namespace Orthanc -{ - class DicomValue : public boost::noncopyable - { - private: - enum Type - { - Type_Null, - Type_String, - Type_Binary - }; - - Type type_; - std::string content_; - - DicomValue(const DicomValue& other); - - public: - DicomValue() : type_(Type_Null) - { - } - - DicomValue(const std::string& content, - bool isBinary); - - DicomValue(const char* data, - size_t size, - bool isBinary); - - const std::string& GetContent() const; - - bool IsNull() const - { - return type_ == Type_Null; - } - - bool IsBinary() const - { - return type_ == Type_Binary; - } - - DicomValue* Clone() const; - -#if ORTHANC_ENABLE_BASE64 == 1 - void FormatDataUriScheme(std::string& target, - const std::string& mime) const; - - void FormatDataUriScheme(std::string& target) const - { - FormatDataUriScheme(target, MIME_BINARY); - } -#endif - - bool CopyToString(std::string& result, - bool allowBinary) const; - - bool ParseInteger32(int32_t& result) const; - - bool ParseInteger64(int64_t& result) const; - - bool ParseUnsignedInteger32(uint32_t& result) const; - - bool ParseUnsignedInteger64(uint64_t& result) const; - - bool ParseFloat(float& result) const; - - bool ParseDouble(double& result) const; - - bool ParseFirstFloat(float& result) const; - - bool ParseFirstUnsignedInteger(unsigned int& result) const; - - void Serialize(Json::Value& target) const; - - void Unserialize(const Json::Value& source); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,860 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomAssociation.h" - -#if !defined(DCMTK_VERSION_NUMBER) -# error The macro DCMTK_VERSION_NUMBER must be defined -#endif - -#include "../Compatibility.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "NetworkingCompatibility.h" - -#include // For dcmConnectionTimeout() -#include - -namespace Orthanc -{ - static void FillSopSequence(DcmDataset& dataset, - const DcmTagKey& tag, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::vector& failureReasons, - bool hasFailureReasons) - { - assert(sopClassUids.size() == sopInstanceUids.size() && - (hasFailureReasons ? - failureReasons.size() == sopClassUids.size() : - failureReasons.empty())); - - if (sopInstanceUids.empty()) - { - // Add an empty sequence - if (!dataset.insertEmptyElement(tag).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - for (size_t i = 0; i < sopClassUids.size(); i++) - { - std::unique_ptr item(new DcmItem); - if (!item->putAndInsertString(DCM_ReferencedSOPClassUID, sopClassUids[i].c_str()).good() || - !item->putAndInsertString(DCM_ReferencedSOPInstanceUID, sopInstanceUids[i].c_str()).good() || - (hasFailureReasons && - !item->putAndInsertUint16(DCM_FailureReason, failureReasons[i]).good()) || - !dataset.insertSequenceItem(tag, item.release()).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - } - } - - - void DicomAssociation::Initialize() - { - role_ = DicomAssociationRole_Default; - isOpen_ = false; - net_ = NULL; - params_ = NULL; - assoc_ = NULL; - - // Must be after "isOpen_ = false" - ClearPresentationContexts(); - } - - - void DicomAssociation::CheckConnecting(const DicomAssociationParameters& parameters, - const OFCondition& cond) - { - try - { - CheckCondition(cond, parameters, "connecting"); - } - catch (OrthancException&) - { - CloseInternal(); - throw; - } - } - - - void DicomAssociation::CloseInternal() - { - if (assoc_ != NULL) - { - ASC_releaseAssociation(assoc_); - ASC_destroyAssociation(&assoc_); - assoc_ = NULL; - params_ = NULL; - } - else - { - if (params_ != NULL) - { - ASC_destroyAssociationParameters(¶ms_); - params_ = NULL; - } - } - - if (net_ != NULL) - { - ASC_dropNetwork(&net_); - net_ = NULL; - } - - accepted_.clear(); - isOpen_ = false; - } - - - void DicomAssociation::AddAccepted(const std::string& abstractSyntax, - DicomTransferSyntax syntax, - uint8_t presentationContextId) - { - AcceptedPresentationContexts::iterator found = accepted_.find(abstractSyntax); - - if (found == accepted_.end()) - { - std::map syntaxes; - syntaxes[syntax] = presentationContextId; - accepted_[abstractSyntax] = syntaxes; - } - else - { - if (found->second.find(syntax) != found->second.end()) - { - LOG(WARNING) << "The same transfer syntax (" - << GetTransferSyntaxUid(syntax) - << ") was accepted twice for the same abstract syntax UID (" - << abstractSyntax << ")"; - } - else - { - found->second[syntax] = presentationContextId; - } - } - } - - - DicomAssociation::~DicomAssociation() - { - try - { - Close(); - } - catch (OrthancException& e) - { - // Don't throw exception in destructors - LOG(ERROR) << "Error while destroying a DICOM association: " << e.What(); - } - } - - - void DicomAssociation::SetRole(DicomAssociationRole role) - { - if (role_ != role) - { - Close(); - role_ = role; - } - } - - - void DicomAssociation::ClearPresentationContexts() - { - Close(); - proposed_.clear(); - proposed_.reserve(MAX_PROPOSED_PRESENTATIONS); - } - - - void DicomAssociation::Open(const DicomAssociationParameters& parameters) - { - if (isOpen_) - { - return; // Already open - } - - // Timeout used during association negociation and ASC_releaseAssociation() - uint32_t acseTimeout = parameters.GetTimeout(); - if (acseTimeout == 0) - { - /** - * Timeout is disabled. Global timeout (seconds) for - * connecting to remote hosts. Default value is -1 which - * selects infinite timeout, i.e. blocking connect(). - **/ - dcmConnectionTimeout.set(-1); - acseTimeout = 10; - } - else - { - dcmConnectionTimeout.set(acseTimeout); - } - - T_ASC_SC_ROLE dcmtkRole; - switch (role_) - { - case DicomAssociationRole_Default: - dcmtkRole = ASC_SC_ROLE_DEFAULT; - break; - - case DicomAssociationRole_Scu: - dcmtkRole = ASC_SC_ROLE_SCU; - break; - - case DicomAssociationRole_Scp: - dcmtkRole = ASC_SC_ROLE_SCP; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - assert(net_ == NULL && - params_ == NULL && - assoc_ == NULL); - - if (proposed_.empty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "No presentation context was proposed"); - } - - LOG(INFO) << "Opening a DICOM SCU connection from AET \"" - << parameters.GetLocalApplicationEntityTitle() - << "\" to AET \"" << parameters.GetRemoteModality().GetApplicationEntityTitle() - << "\" on host " << parameters.GetRemoteModality().GetHost() - << ":" << parameters.GetRemoteModality().GetPortNumber() - << " (manufacturer: " << EnumerationToString(parameters.GetRemoteModality().GetManufacturer()) << ")"; - - CheckConnecting(parameters, ASC_initializeNetwork(NET_REQUESTOR, 0, /*opt_acse_timeout*/ acseTimeout, &net_)); - CheckConnecting(parameters, ASC_createAssociationParameters(¶ms_, /*opt_maxReceivePDULength*/ ASC_DEFAULTMAXPDU)); - - // Set this application's title and the called application's title in the params - CheckConnecting(parameters, ASC_setAPTitles( - params_, parameters.GetLocalApplicationEntityTitle().c_str(), - parameters.GetRemoteModality().GetApplicationEntityTitle().c_str(), NULL)); - - // Set the network addresses of the local and remote entities - char localHost[HOST_NAME_MAX]; - gethostname(localHost, HOST_NAME_MAX - 1); - - char remoteHostAndPort[HOST_NAME_MAX]; - -#ifdef _MSC_VER - _snprintf -#else - snprintf -#endif - (remoteHostAndPort, HOST_NAME_MAX - 1, "%s:%d", - parameters.GetRemoteModality().GetHost().c_str(), - parameters.GetRemoteModality().GetPortNumber()); - - CheckConnecting(parameters, ASC_setPresentationAddresses(params_, localHost, remoteHostAndPort)); - - // Set various options - CheckConnecting(parameters, ASC_setTransportLayerType(params_, /*opt_secureConnection*/ false)); - - // Setup the list of proposed presentation contexts - unsigned int presentationContextId = 1; - for (size_t i = 0; i < proposed_.size(); i++) - { - assert(presentationContextId <= 255); - const char* abstractSyntax = proposed_[i].abstractSyntax_.c_str(); - - const std::set& source = proposed_[i].transferSyntaxes_; - - std::vector transferSyntaxes; - transferSyntaxes.reserve(source.size()); - - for (std::set::const_iterator - it = source.begin(); it != source.end(); ++it) - { - transferSyntaxes.push_back(GetTransferSyntaxUid(*it)); - } - - assert(!transferSyntaxes.empty()); - CheckConnecting(parameters, ASC_addPresentationContext( - params_, presentationContextId, abstractSyntax, - &transferSyntaxes[0], transferSyntaxes.size(), dcmtkRole)); - - presentationContextId += 2; - } - - // Do the association - CheckConnecting(parameters, ASC_requestAssociation(net_, params_, &assoc_)); - isOpen_ = true; - - // Inspect the accepted transfer syntaxes - LST_HEAD **l = ¶ms_->DULparams.acceptedPresentationContext; - if (*l != NULL) - { - DUL_PRESENTATIONCONTEXT* pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l); - LST_Position(l, (LST_NODE*)pc); - while (pc) - { - if (pc->result == ASC_P_ACCEPTANCE) - { - DicomTransferSyntax transferSyntax; - if (LookupTransferSyntax(transferSyntax, pc->acceptedTransferSyntax)) - { - AddAccepted(pc->abstractSyntax, transferSyntax, pc->presentationContextID); - } - else - { - LOG(WARNING) << "Unknown transfer syntax received from AET \"" - << parameters.GetRemoteModality().GetApplicationEntityTitle() - << "\": " << pc->acceptedTransferSyntax; - } - } - - pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l); - } - } - - if (accepted_.empty()) - { - throw OrthancException(ErrorCode_NoPresentationContext, - "Unable to negotiate a presentation context with AET \"" + - parameters.GetRemoteModality().GetApplicationEntityTitle() + "\""); - } - } - - void DicomAssociation::Close() - { - if (isOpen_) - { - CloseInternal(); - } - } - - - bool DicomAssociation::LookupAcceptedPresentationContext(std::map& target, - const std::string& abstractSyntax) const - { - if (!IsOpen()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, "Connection not opened"); - } - - AcceptedPresentationContexts::const_iterator found = accepted_.find(abstractSyntax); - - if (found == accepted_.end()) - { - return false; - } - else - { - target = found->second; - return true; - } - } - - - void DicomAssociation::ProposeGenericPresentationContext(const std::string& abstractSyntax) - { - std::set ts; - ts.insert(DicomTransferSyntax_LittleEndianImplicit); - ts.insert(DicomTransferSyntax_LittleEndianExplicit); - ts.insert(DicomTransferSyntax_BigEndianExplicit); // Retired - ProposePresentationContext(abstractSyntax, ts); - } - - - void DicomAssociation::ProposePresentationContext(const std::string& abstractSyntax, - DicomTransferSyntax transferSyntax) - { - std::set ts; - ts.insert(transferSyntax); - ProposePresentationContext(abstractSyntax, ts); - } - - - size_t DicomAssociation::GetRemainingPropositions() const - { - assert(proposed_.size() <= MAX_PROPOSED_PRESENTATIONS); - return MAX_PROPOSED_PRESENTATIONS - proposed_.size(); - } - - - void DicomAssociation::ProposePresentationContext( - const std::string& abstractSyntax, - const std::set& transferSyntaxes) - { - if (transferSyntaxes.empty()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "No transfer syntax provided"); - } - - if (proposed_.size() >= MAX_PROPOSED_PRESENTATIONS) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Too many proposed presentation contexts"); - } - - if (IsOpen()) - { - Close(); - } - - ProposedPresentationContext context; - context.abstractSyntax_ = abstractSyntax; - context.transferSyntaxes_ = transferSyntaxes; - - proposed_.push_back(context); - } - - - T_ASC_Association& DicomAssociation::GetDcmtkAssociation() const - { - if (isOpen_) - { - assert(assoc_ != NULL); - return *assoc_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "The connection is not open"); - } - } - - - T_ASC_Network& DicomAssociation::GetDcmtkNetwork() const - { - if (isOpen_) - { - assert(net_ != NULL); - return *net_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "The connection is not open"); - } - } - - - void DicomAssociation::CheckCondition(const OFCondition& cond, - const DicomAssociationParameters& parameters, - const std::string& command) - { - if (cond.bad()) - { - // Reformat the error message from DCMTK by turning multiline - // errors into a single line - - std::string s(cond.text()); - std::string info; - info.reserve(s.size()); - - bool isMultiline = false; - for (size_t i = 0; i < s.size(); i++) - { - if (s[i] == '\r') - { - // Ignore - } - else if (s[i] == '\n') - { - if (isMultiline) - { - info += "; "; - } - else - { - info += " ("; - isMultiline = true; - } - } - else - { - info.push_back(s[i]); - } - } - - if (isMultiline) - { - info += ")"; - } - - throw OrthancException(ErrorCode_NetworkProtocol, - "DicomAssociation - " + command + " to AET \"" + - parameters.GetRemoteModality().GetApplicationEntityTitle() + - "\": " + info); - } - } - - - void DicomAssociation::ReportStorageCommitment( - const DicomAssociationParameters& parameters, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::vector& failureReasons) - { - if (sopClassUids.size() != sopInstanceUids.size() || - sopClassUids.size() != failureReasons.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - std::vector successSopClassUids, successSopInstanceUids, failedSopClassUids, failedSopInstanceUids; - std::vector failedReasons; - - successSopClassUids.reserve(sopClassUids.size()); - successSopInstanceUids.reserve(sopClassUids.size()); - failedSopClassUids.reserve(sopClassUids.size()); - failedSopInstanceUids.reserve(sopClassUids.size()); - failedReasons.reserve(sopClassUids.size()); - - for (size_t i = 0; i < sopClassUids.size(); i++) - { - switch (failureReasons[i]) - { - case StorageCommitmentFailureReason_Success: - successSopClassUids.push_back(sopClassUids[i]); - successSopInstanceUids.push_back(sopInstanceUids[i]); - break; - - case StorageCommitmentFailureReason_ProcessingFailure: - case StorageCommitmentFailureReason_NoSuchObjectInstance: - case StorageCommitmentFailureReason_ResourceLimitation: - case StorageCommitmentFailureReason_ReferencedSOPClassNotSupported: - case StorageCommitmentFailureReason_ClassInstanceConflict: - case StorageCommitmentFailureReason_DuplicateTransactionUID: - failedSopClassUids.push_back(sopClassUids[i]); - failedSopInstanceUids.push_back(sopInstanceUids[i]); - failedReasons.push_back(failureReasons[i]); - break; - - default: - { - char buf[16]; - sprintf(buf, "%04xH", failureReasons[i]); - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Unsupported failure reason for storage commitment: " + std::string(buf)); - } - } - } - - DicomAssociation association; - - { - std::set transferSyntaxes; - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); - - association.SetRole(DicomAssociationRole_Scp); - association.ProposePresentationContext(UID_StorageCommitmentPushModelSOPClass, - transferSyntaxes); - } - - association.Open(parameters); - - /** - * N-EVENT-REPORT - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#table_10.1-1 - * - * Status code: - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#sect_10.1.1.1.8 - **/ - - /** - * Send the "EVENT_REPORT_RQ" request - **/ - - LOG(INFO) << "Reporting modality \"" - << parameters.GetRemoteModality().GetApplicationEntityTitle() - << "\" about storage commitment transaction: " << transactionUid - << " (" << successSopClassUids.size() << " successes, " - << failedSopClassUids.size() << " failures)"; - const DIC_US messageId = association.GetDcmtkAssociation().nextMsgID++; - - { - T_DIMSE_Message message; - memset(&message, 0, sizeof(message)); - message.CommandField = DIMSE_N_EVENT_REPORT_RQ; - - T_DIMSE_N_EventReportRQ& content = message.msg.NEventReportRQ; - content.MessageID = messageId; - strncpy(content.AffectedSOPClassUID, UID_StorageCommitmentPushModelSOPClass, DIC_UI_LEN); - strncpy(content.AffectedSOPInstanceUID, UID_StorageCommitmentPushModelSOPInstance, DIC_UI_LEN); - content.DataSetType = DIMSE_DATASET_PRESENT; - - DcmDataset dataset; - if (!dataset.putAndInsertString(DCM_TransactionUID, transactionUid.c_str()).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - - { - std::vector empty; - FillSopSequence(dataset, DCM_ReferencedSOPSequence, successSopClassUids, - successSopInstanceUids, empty, false); - } - - // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html - if (failedSopClassUids.empty()) - { - content.EventTypeID = 1; // "Storage Commitment Request Successful" - } - else - { - content.EventTypeID = 2; // "Storage Commitment Request Complete - Failures Exist" - - // Failure reason - // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part03/sect_C.14.html#sect_C.14.1.1 - FillSopSequence(dataset, DCM_FailedSOPSequence, failedSopClassUids, - failedSopInstanceUids, failedReasons, true); - } - - int presID = ASC_findAcceptedPresentationContextID( - &association.GetDcmtkAssociation(), UID_StorageCommitmentPushModelSOPClass); - if (presID == 0) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "Unable to send N-EVENT-REPORT request to AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - - if (!DIMSE_sendMessageUsingMemoryData( - &association.GetDcmtkAssociation(), presID, &message, NULL /* status detail */, - &dataset, NULL /* callback */, NULL /* callback context */, - NULL /* commandSet */).good()) - { - throw OrthancException(ErrorCode_NetworkProtocol); - } - } - - /** - * Read the "EVENT_REPORT_RSP" response - **/ - - { - T_ASC_PresentationContextID presID = 0; - T_DIMSE_Message message; - - if (!DIMSE_receiveCommand(&association.GetDcmtkAssociation(), - (parameters.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - parameters.GetTimeout(), &presID, &message, - NULL /* no statusDetail */).good() || - message.CommandField != DIMSE_N_EVENT_REPORT_RSP) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "Unable to read N-EVENT-REPORT response from AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - - const T_DIMSE_N_EventReportRSP& content = message.msg.NEventReportRSP; - if (content.MessageIDBeingRespondedTo != messageId || - !(content.opts & O_NEVENTREPORT_AFFECTEDSOPCLASSUID) || - !(content.opts & O_NEVENTREPORT_AFFECTEDSOPINSTANCEUID) || - //(content.opts & O_NEVENTREPORT_EVENTTYPEID) || // Pedantic test - The "content.EventTypeID" is not used by Orthanc - std::string(content.AffectedSOPClassUID) != UID_StorageCommitmentPushModelSOPClass || - std::string(content.AffectedSOPInstanceUID) != UID_StorageCommitmentPushModelSOPInstance || - content.DataSetType != DIMSE_DATASET_NULL) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "Badly formatted N-EVENT-REPORT response from AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - - if (content.DimseStatus != 0 /* success */) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "The request cannot be handled by remote AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - } - - association.Close(); - } - - - void DicomAssociation::RequestStorageCommitment( - const DicomAssociationParameters& parameters, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids) - { - if (sopClassUids.size() != sopInstanceUids.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - for (size_t i = 0; i < sopClassUids.size(); i++) - { - if (sopClassUids[i].empty() || - sopInstanceUids[i].empty()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "The SOP class/instance UIDs cannot be empty, found: \"" + - sopClassUids[i] + "\" / \"" + sopInstanceUids[i] + "\""); - } - } - - if (transactionUid.size() < 5 || - transactionUid.substr(0, 5) != "2.25.") - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - DicomAssociation association; - - { - std::set transferSyntaxes; - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - transferSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); - - association.SetRole(DicomAssociationRole_Default); - association.ProposePresentationContext(UID_StorageCommitmentPushModelSOPClass, - transferSyntaxes); - } - - association.Open(parameters); - - /** - * N-ACTION - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.2.html - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#table_10.1-4 - * - * Status code: - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#sect_10.1.1.1.8 - **/ - - /** - * Send the "N_ACTION_RQ" request - **/ - - LOG(INFO) << "Request to modality \"" - << parameters.GetRemoteModality().GetApplicationEntityTitle() - << "\" about storage commitment for " << sopClassUids.size() - << " instances, with transaction UID: " << transactionUid; - const DIC_US messageId = association.GetDcmtkAssociation().nextMsgID++; - - { - T_DIMSE_Message message; - memset(&message, 0, sizeof(message)); - message.CommandField = DIMSE_N_ACTION_RQ; - - T_DIMSE_N_ActionRQ& content = message.msg.NActionRQ; - content.MessageID = messageId; - strncpy(content.RequestedSOPClassUID, UID_StorageCommitmentPushModelSOPClass, DIC_UI_LEN); - strncpy(content.RequestedSOPInstanceUID, UID_StorageCommitmentPushModelSOPInstance, DIC_UI_LEN); - content.ActionTypeID = 1; // "Request Storage Commitment" - content.DataSetType = DIMSE_DATASET_PRESENT; - - DcmDataset dataset; - if (!dataset.putAndInsertString(DCM_TransactionUID, transactionUid.c_str()).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - - { - std::vector empty; - FillSopSequence(dataset, DCM_ReferencedSOPSequence, sopClassUids, sopInstanceUids, empty, false); - } - - int presID = ASC_findAcceptedPresentationContextID( - &association.GetDcmtkAssociation(), UID_StorageCommitmentPushModelSOPClass); - if (presID == 0) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "Unable to send N-ACTION request to AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - - if (!DIMSE_sendMessageUsingMemoryData( - &association.GetDcmtkAssociation(), presID, &message, NULL /* status detail */, - &dataset, NULL /* callback */, NULL /* callback context */, - NULL /* commandSet */).good()) - { - throw OrthancException(ErrorCode_NetworkProtocol); - } - } - - /** - * Read the "N_ACTION_RSP" response - **/ - - { - T_ASC_PresentationContextID presID = 0; - T_DIMSE_Message message; - - if (!DIMSE_receiveCommand(&association.GetDcmtkAssociation(), - (parameters.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - parameters.GetTimeout(), &presID, &message, - NULL /* no statusDetail */).good() || - message.CommandField != DIMSE_N_ACTION_RSP) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "Unable to read N-ACTION response from AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - - const T_DIMSE_N_ActionRSP& content = message.msg.NActionRSP; - if (content.MessageIDBeingRespondedTo != messageId || - !(content.opts & O_NACTION_AFFECTEDSOPCLASSUID) || - !(content.opts & O_NACTION_AFFECTEDSOPINSTANCEUID) || - //(content.opts & O_NACTION_ACTIONTYPEID) || // Pedantic test - The "content.ActionTypeID" is not used by Orthanc - std::string(content.AffectedSOPClassUID) != UID_StorageCommitmentPushModelSOPClass || - std::string(content.AffectedSOPInstanceUID) != UID_StorageCommitmentPushModelSOPInstance || - content.DataSetType != DIMSE_DATASET_NULL) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "Badly formatted N-ACTION response from AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - - if (content.DimseStatus != 0 /* success */) - { - throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " - "The request cannot be handled by remote AET: " + - parameters.GetRemoteModality().GetApplicationEntityTitle()); - } - } - - association.Close(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1 -# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be set to 1 -#endif - -#include "DicomAssociationParameters.h" - -#include - -#include // For uint8_t -#include -#include - -namespace Orthanc -{ - class DicomAssociation : public boost::noncopyable - { - private: - // This is the maximum number of presentation context IDs (the - // number of odd integers between 1 and 255) - // http://dicom.nema.org/medical/dicom/2019e/output/chtml/part08/sect_9.3.2.2.html - static const size_t MAX_PROPOSED_PRESENTATIONS = 128; - - struct ProposedPresentationContext - { - std::string abstractSyntax_; - std::set transferSyntaxes_; - }; - - typedef std::map > - AcceptedPresentationContexts; - - DicomAssociationRole role_; - bool isOpen_; - std::vector proposed_; - AcceptedPresentationContexts accepted_; - T_ASC_Network* net_; - T_ASC_Parameters* params_; - T_ASC_Association* assoc_; - - void Initialize(); - - void CheckConnecting(const DicomAssociationParameters& parameters, - const OFCondition& cond); - - void CloseInternal(); - - void AddAccepted(const std::string& abstractSyntax, - DicomTransferSyntax syntax, - uint8_t presentationContextId); - - public: - DicomAssociation() - { - Initialize(); - } - - ~DicomAssociation(); - - bool IsOpen() const - { - return isOpen_; - } - - void SetRole(DicomAssociationRole role); - - void ClearPresentationContexts(); - - void Open(const DicomAssociationParameters& parameters); - - void Close(); - - bool LookupAcceptedPresentationContext( - std::map& target, - const std::string& abstractSyntax) const; - - void ProposeGenericPresentationContext(const std::string& abstractSyntax); - - void ProposePresentationContext(const std::string& abstractSyntax, - DicomTransferSyntax transferSyntax); - - size_t GetRemainingPropositions() const; - - void ProposePresentationContext( - const std::string& abstractSyntax, - const std::set& transferSyntaxes); - - T_ASC_Association& GetDcmtkAssociation() const; - - T_ASC_Network& GetDcmtkNetwork() const; - - static void CheckCondition(const OFCondition& cond, - const DicomAssociationParameters& parameters, - const std::string& command); - - static void ReportStorageCommitment( - const DicomAssociationParameters& parameters, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::vector& failureReasons); - - static void RequestStorageCommitment( - const DicomAssociationParameters& parameters, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomAssociationParameters.h" - -#include "../Compatibility.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../SerializationToolbox.h" -#include "NetworkingCompatibility.h" - -#include - -// By default, the timeout for client DICOM connections is set to 10 seconds -static boost::mutex defaultTimeoutMutex_; -static uint32_t defaultTimeout_ = 10; - - -namespace Orthanc -{ - void DicomAssociationParameters::CheckHost(const std::string& host) - { - if (host.size() > HOST_NAME_MAX - 10) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Invalid host name (too long): " + host); - } - } - - - uint32_t DicomAssociationParameters::GetDefaultTimeout() - { - boost::mutex::scoped_lock lock(defaultTimeoutMutex_); - return defaultTimeout_; - } - - - DicomAssociationParameters::DicomAssociationParameters() : - localAet_("ORTHANC"), - timeout_(GetDefaultTimeout()) - { - remote_.SetApplicationEntityTitle("ANY-SCP"); - } - - - DicomAssociationParameters::DicomAssociationParameters(const std::string& localAet, - const RemoteModalityParameters& remote) : - localAet_(localAet), - timeout_(GetDefaultTimeout()) - { - SetRemoteModality(remote); - } - - - void DicomAssociationParameters::SetRemoteModality(const RemoteModalityParameters& remote) - { - CheckHost(remote.GetHost()); - remote_ = remote; - } - - - void DicomAssociationParameters::SetRemoteHost(const std::string& host) - { - CheckHost(host); - remote_.SetHost(host); - } - - - bool DicomAssociationParameters::IsEqual(const DicomAssociationParameters& other) const - { - return (localAet_ == other.localAet_ && - remote_.GetApplicationEntityTitle() == other.remote_.GetApplicationEntityTitle() && - remote_.GetHost() == other.remote_.GetHost() && - remote_.GetPortNumber() == other.remote_.GetPortNumber() && - remote_.GetManufacturer() == other.remote_.GetManufacturer() && - timeout_ == other.timeout_); - } - - - static const char* const LOCAL_AET = "LocalAet"; - static const char* const REMOTE = "Remote"; - static const char* const TIMEOUT = "Timeout"; // New in Orthanc in 1.7.0 - - - void DicomAssociationParameters::SerializeJob(Json::Value& target) const - { - if (target.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - target[LOCAL_AET] = localAet_; - remote_.Serialize(target[REMOTE], true /* force advanced format */); - target[TIMEOUT] = timeout_; - } - } - - - DicomAssociationParameters DicomAssociationParameters::UnserializeJob(const Json::Value& serialized) - { - if (serialized.type() == Json::objectValue) - { - DicomAssociationParameters result; - - result.remote_ = RemoteModalityParameters(serialized[REMOTE]); - result.localAet_ = SerializationToolbox::ReadString(serialized, LOCAL_AET); - result.timeout_ = SerializationToolbox::ReadInteger(serialized, TIMEOUT, GetDefaultTimeout()); - - return result; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - void DicomAssociationParameters::SetDefaultTimeout(uint32_t seconds) - { - LOG(INFO) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): " - << seconds << " seconds (0 = no timeout)"; - - { - boost::mutex::scoped_lock lock(defaultTimeoutMutex_); - defaultTimeout_ = seconds; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomAssociationParameters.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RemoteModalityParameters.h" - -#include - -class OFCondition; // From DCMTK - -namespace Orthanc -{ - class DicomAssociationParameters - { - private: - std::string localAet_; - RemoteModalityParameters remote_; - uint32_t timeout_; - - static void CheckHost(const std::string& host); - - public: - DicomAssociationParameters(); - - DicomAssociationParameters(const std::string& localAet, - const RemoteModalityParameters& remote); - - const std::string& GetLocalApplicationEntityTitle() const - { - return localAet_; - } - - void SetLocalApplicationEntityTitle(const std::string& aet) - { - localAet_ = aet; - } - - const RemoteModalityParameters& GetRemoteModality() const - { - return remote_; - } - - void SetRemoteModality(const RemoteModalityParameters& parameters); - - void SetRemoteApplicationEntityTitle(const std::string& aet) - { - remote_.SetApplicationEntityTitle(aet); - } - - void SetRemoteHost(const std::string& host); - - void SetRemotePort(uint16_t port) - { - remote_.SetPortNumber(port); - } - - void SetRemoteManufacturer(ModalityManufacturer manufacturer) - { - remote_.SetManufacturer(manufacturer); - } - - bool IsEqual(const DicomAssociationParameters& other) const; - - // Setting it to "0" disables the timeout (infinite wait) - void SetTimeout(uint32_t seconds) - { - timeout_ = seconds; - } - - uint32_t GetTimeout() const - { - return timeout_; - } - - bool HasTimeout() const - { - return timeout_ != 0; - } - - void SerializeJob(Json::Value& target) const; - - static DicomAssociationParameters UnserializeJob(const Json::Value& serialized); - - static void SetDefaultTimeout(uint32_t seconds); - - static uint32_t GetDefaultTimeout(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,672 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomControlUserConnection.h" - -#include "../Compatibility.h" -#include "../DicomParsing/FromDcmtkBridge.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "DicomAssociation.h" - -#include -#include - -namespace Orthanc -{ - static void TestAndCopyTag(DicomMap& result, - const DicomMap& source, - const DicomTag& tag) - { - if (!source.HasTag(tag)) - { - throw OrthancException(ErrorCode_BadRequest); - } - else - { - result.SetValue(tag, source.GetValue(tag)); - } - } - - - namespace - { - struct FindPayload - { - DicomFindAnswers* answers; - const char* level; - bool isWorklist; - }; - } - - - static void FindCallback( - /* in */ - void *callbackData, - T_DIMSE_C_FindRQ *request, /* original find request */ - int responseCount, - T_DIMSE_C_FindRSP *response, /* pending response received */ - DcmDataset *responseIdentifiers /* pending response identifiers */ - ) - { - FindPayload& payload = *reinterpret_cast(callbackData); - - if (responseIdentifiers != NULL) - { - if (payload.isWorklist) - { - ParsedDicomFile answer(*responseIdentifiers); - payload.answers->Add(answer); - } - else - { - DicomMap m; - FromDcmtkBridge::ExtractDicomSummary(m, *responseIdentifiers); - - if (!m.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL)) - { - m.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, payload.level, false); - } - - payload.answers->Add(m); - } - } - } - - - static void NormalizeFindQuery(DicomMap& fixedQuery, - ResourceType level, - const DicomMap& fields) - { - std::set allowedTags; - - // WARNING: Do not add "break" or reorder items in this switch-case! - switch (level) - { - case ResourceType_Instance: - DicomTag::AddTagsForModule(allowedTags, DicomModule_Instance); - - case ResourceType_Series: - DicomTag::AddTagsForModule(allowedTags, DicomModule_Series); - - case ResourceType_Study: - DicomTag::AddTagsForModule(allowedTags, DicomModule_Study); - - case ResourceType_Patient: - DicomTag::AddTagsForModule(allowedTags, DicomModule_Patient); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - switch (level) - { - case ResourceType_Patient: - allowedTags.insert(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES); - allowedTags.insert(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES); - allowedTags.insert(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES); - break; - - case ResourceType_Study: - allowedTags.insert(DICOM_TAG_MODALITIES_IN_STUDY); - allowedTags.insert(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES); - allowedTags.insert(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES); - allowedTags.insert(DICOM_TAG_SOP_CLASSES_IN_STUDY); - break; - - case ResourceType_Series: - allowedTags.insert(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES); - break; - - default: - break; - } - - allowedTags.insert(DICOM_TAG_SPECIFIC_CHARACTER_SET); - - DicomArray query(fields); - for (size_t i = 0; i < query.GetSize(); i++) - { - const DicomTag& tag = query.GetElement(i).GetTag(); - if (allowedTags.find(tag) == allowedTags.end()) - { - LOG(WARNING) << "Tag not allowed for this C-Find level, will be ignored: " << tag; - } - else - { - fixedQuery.SetValue(tag, query.GetElement(i).GetValue()); - } - } - } - - - - static ParsedDicomFile* ConvertQueryFields(const DicomMap& fields, - ModalityManufacturer manufacturer) - { - // Fix outgoing C-Find requests issue for Syngo.Via and its - // solution was reported by Emsy Chan by private mail on - // 2015-06-17. According to Robert van Ommen (2015-11-30), the - // same fix is required for Agfa Impax. This was generalized for - // generic manufacturer since it seems to affect PhilipsADW, - // GEWAServer as well: - // https://bitbucket.org/sjodogne/orthanc/issues/31/ - - switch (manufacturer) - { - case ModalityManufacturer_GenericNoWildcardInDates: - case ModalityManufacturer_GenericNoUniversalWildcard: - { - std::unique_ptr fix(fields.Clone()); - - std::set tags; - fix->GetTags(tags); - - for (std::set::const_iterator it = tags.begin(); it != tags.end(); ++it) - { - // Replace a "*" wildcard query by an empty query ("") for - // "date" or "all" value representations depending on the - // type of manufacturer. - if (manufacturer == ModalityManufacturer_GenericNoUniversalWildcard || - (manufacturer == ModalityManufacturer_GenericNoWildcardInDates && - FromDcmtkBridge::LookupValueRepresentation(*it) == ValueRepresentation_Date)) - { - const DicomValue* value = fix->TestAndGetValue(*it); - - if (value != NULL && - !value->IsNull() && - value->GetContent() == "*") - { - fix->SetValue(*it, "", false); - } - } - } - - return new ParsedDicomFile(*fix, GetDefaultDicomEncoding(), false /* be strict */); - } - - default: - return new ParsedDicomFile(fields, GetDefaultDicomEncoding(), false /* be strict */); - } - } - - - - void DicomControlUserConnection::SetupPresentationContexts() - { - assert(association_.get() != NULL); - association_->ProposeGenericPresentationContext(UID_VerificationSOPClass); - association_->ProposeGenericPresentationContext(UID_FINDPatientRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_FINDStudyRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_MOVEStudyRootQueryRetrieveInformationModel); - association_->ProposeGenericPresentationContext(UID_FINDModalityWorklistInformationModel); - } - - - void DicomControlUserConnection::FindInternal(DicomFindAnswers& answers, - DcmDataset* dataset, - const char* sopClass, - bool isWorklist, - const char* level) - { - assert(isWorklist ^ (level != NULL)); - assert(association_.get() != NULL); - - association_->Open(parameters_); - - FindPayload payload; - payload.answers = &answers; - payload.level = level; - payload.isWorklist = isWorklist; - - // Figure out which of the accepted presentation contexts should be used - int presID = ASC_findAcceptedPresentationContextID( - &association_->GetDcmtkAssociation(), sopClass); - if (presID == 0) - { - throw OrthancException(ErrorCode_DicomFindUnavailable, - "Remote AET is " + parameters_.GetRemoteModality().GetApplicationEntityTitle()); - } - - T_DIMSE_C_FindRQ request; - memset(&request, 0, sizeof(request)); - request.MessageID = association_->GetDcmtkAssociation().nextMsgID++; - strncpy(request.AffectedSOPClassUID, sopClass, DIC_UI_LEN); - request.Priority = DIMSE_PRIORITY_MEDIUM; - request.DataSetType = DIMSE_DATASET_PRESENT; - - T_DIMSE_C_FindRSP response; - DcmDataset* statusDetail = NULL; - -#if DCMTK_VERSION_NUMBER >= 364 - int responseCount; -#endif - - OFCondition cond = DIMSE_findUser( - &association_->GetDcmtkAssociation(), presID, &request, dataset, -#if DCMTK_VERSION_NUMBER >= 364 - responseCount, -#endif - FindCallback, &payload, - /*opt_blockMode*/ (parameters_.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ parameters_.GetTimeout(), - &response, &statusDetail); - - if (statusDetail) - { - delete statusDetail; - } - - DicomAssociation::CheckCondition(cond, parameters_, "C-FIND"); - - - /** - * New in Orthanc 1.6.0: Deal with failures during C-FIND. - * http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.html#table_C.4-1 - **/ - - if (response.DimseStatus != 0x0000 && // Success - response.DimseStatus != 0xFF00 && // Pending - Matches are continuing - response.DimseStatus != 0xFF01) // Pending - Matches are continuing - { - char buf[16]; - sprintf(buf, "%04X", response.DimseStatus); - - if (response.DimseStatus == STATUS_FIND_Failed_UnableToProcess) - { - throw OrthancException(ErrorCode_NetworkProtocol, - HttpStatus_422_UnprocessableEntity, - "C-FIND SCU to AET \"" + - parameters_.GetRemoteModality().GetApplicationEntityTitle() + - "\" has failed with DIMSE status 0x" + buf + - " (unable to process - invalid query ?)"); - } - else - { - throw OrthancException(ErrorCode_NetworkProtocol, "C-FIND SCU to AET \"" + - parameters_.GetRemoteModality().GetApplicationEntityTitle() + - "\" has failed with DIMSE status 0x" + buf); - } - } - } - - - void DicomControlUserConnection::MoveInternal(const std::string& targetAet, - ResourceType level, - const DicomMap& fields) - { - assert(association_.get() != NULL); - association_->Open(parameters_); - - std::unique_ptr query( - ConvertQueryFields(fields, parameters_.GetRemoteModality().GetManufacturer())); - DcmDataset* dataset = query->GetDcmtkObject().getDataset(); - - const char* sopClass = UID_MOVEStudyRootQueryRetrieveInformationModel; - switch (level) - { - case ResourceType_Patient: - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "PATIENT"); - break; - - case ResourceType_Study: - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "STUDY"); - break; - - case ResourceType_Series: - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "SERIES"); - break; - - case ResourceType_Instance: - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "IMAGE"); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - // Figure out which of the accepted presentation contexts should be used - int presID = ASC_findAcceptedPresentationContextID(&association_->GetDcmtkAssociation(), sopClass); - if (presID == 0) - { - throw OrthancException(ErrorCode_DicomMoveUnavailable, - "Remote AET is " + parameters_.GetRemoteModality().GetApplicationEntityTitle()); - } - - T_DIMSE_C_MoveRQ request; - memset(&request, 0, sizeof(request)); - request.MessageID = association_->GetDcmtkAssociation().nextMsgID++; - strncpy(request.AffectedSOPClassUID, sopClass, DIC_UI_LEN); - request.Priority = DIMSE_PRIORITY_MEDIUM; - request.DataSetType = DIMSE_DATASET_PRESENT; - strncpy(request.MoveDestination, targetAet.c_str(), DIC_AE_LEN); - - T_DIMSE_C_MoveRSP response; - DcmDataset* statusDetail = NULL; - DcmDataset* responseIdentifiers = NULL; - OFCondition cond = DIMSE_moveUser( - &association_->GetDcmtkAssociation(), presID, &request, dataset, NULL, NULL, - /*opt_blockMode*/ (parameters_.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ parameters_.GetTimeout(), - &association_->GetDcmtkNetwork(), NULL, NULL, - &response, &statusDetail, &responseIdentifiers); - - if (statusDetail) - { - delete statusDetail; - } - - if (responseIdentifiers) - { - delete responseIdentifiers; - } - - DicomAssociation::CheckCondition(cond, parameters_, "C-MOVE"); - - - /** - * New in Orthanc 1.6.0: Deal with failures during C-MOVE. - * http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.2.html#table_C.4-2 - **/ - - if (response.DimseStatus != 0x0000 && // Success - response.DimseStatus != 0xFF00) // Pending - Sub-operations are continuing - { - char buf[16]; - sprintf(buf, "%04X", response.DimseStatus); - - if (response.DimseStatus == STATUS_MOVE_Failed_UnableToProcess) - { - throw OrthancException(ErrorCode_NetworkProtocol, - HttpStatus_422_UnprocessableEntity, - "C-MOVE SCU to AET \"" + - parameters_.GetRemoteModality().GetApplicationEntityTitle() + - "\" has failed with DIMSE status 0x" + buf + - " (unable to process - resource not found ?)"); - } - else - { - throw OrthancException(ErrorCode_NetworkProtocol, "C-MOVE SCU to AET \"" + - parameters_.GetRemoteModality().GetApplicationEntityTitle() + - "\" has failed with DIMSE status 0x" + buf); - } - } - } - - - DicomControlUserConnection::DicomControlUserConnection(const DicomAssociationParameters& params) : - parameters_(params), - association_(new DicomAssociation) - { - SetupPresentationContexts(); - } - - - void DicomControlUserConnection::Close() - { - assert(association_.get() != NULL); - association_->Close(); - } - - - bool DicomControlUserConnection::Echo() - { - assert(association_.get() != NULL); - association_->Open(parameters_); - - DIC_US status; - DicomAssociation::CheckCondition( - DIMSE_echoUser(&association_->GetDcmtkAssociation(), - association_->GetDcmtkAssociation().nextMsgID++, - /*opt_blockMode*/ (parameters_.HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ parameters_.GetTimeout(), - &status, NULL), - parameters_, "C-ECHO"); - - return status == STATUS_Success; - } - - - void DicomControlUserConnection::Find(DicomFindAnswers& result, - ResourceType level, - const DicomMap& originalFields, - bool normalize) - { - std::unique_ptr query; - - if (normalize) - { - DicomMap fields; - NormalizeFindQuery(fields, level, originalFields); - query.reset(ConvertQueryFields(fields, parameters_.GetRemoteModality().GetManufacturer())); - } - else - { - query.reset(new ParsedDicomFile(originalFields, - GetDefaultDicomEncoding(), - false /* be strict */)); - } - - DcmDataset* dataset = query->GetDcmtkObject().getDataset(); - - const char* clevel = NULL; - const char* sopClass = NULL; - - switch (level) - { - case ResourceType_Patient: - clevel = "PATIENT"; - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "PATIENT"); - sopClass = UID_FINDPatientRootQueryRetrieveInformationModel; - break; - - case ResourceType_Study: - clevel = "STUDY"; - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "STUDY"); - sopClass = UID_FINDStudyRootQueryRetrieveInformationModel; - break; - - case ResourceType_Series: - clevel = "SERIES"; - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "SERIES"); - sopClass = UID_FINDStudyRootQueryRetrieveInformationModel; - break; - - case ResourceType_Instance: - clevel = "IMAGE"; - DU_putStringDOElement(dataset, DCM_QueryRetrieveLevel, "IMAGE"); - sopClass = UID_FINDStudyRootQueryRetrieveInformationModel; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - const char* universal; - if (parameters_.GetRemoteModality().GetManufacturer() == ModalityManufacturer_GE) - { - universal = "*"; - } - else - { - universal = ""; - } - - - // Add the expected tags for this query level. - // WARNING: Do not reorder or add "break" in this switch-case! - switch (level) - { - case ResourceType_Instance: - if (!dataset->tagExists(DCM_SOPInstanceUID)) - { - DU_putStringDOElement(dataset, DCM_SOPInstanceUID, universal); - } - - case ResourceType_Series: - if (!dataset->tagExists(DCM_SeriesInstanceUID)) - { - DU_putStringDOElement(dataset, DCM_SeriesInstanceUID, universal); - } - - case ResourceType_Study: - if (!dataset->tagExists(DCM_AccessionNumber)) - { - DU_putStringDOElement(dataset, DCM_AccessionNumber, universal); - } - - if (!dataset->tagExists(DCM_StudyInstanceUID)) - { - DU_putStringDOElement(dataset, DCM_StudyInstanceUID, universal); - } - - case ResourceType_Patient: - if (!dataset->tagExists(DCM_PatientID)) - { - DU_putStringDOElement(dataset, DCM_PatientID, universal); - } - - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - assert(clevel != NULL && sopClass != NULL); - FindInternal(result, dataset, sopClass, false, clevel); - } - - - void DicomControlUserConnection::Move(const std::string& targetAet, - ResourceType level, - const DicomMap& findResult) - { - DicomMap move; - switch (level) - { - case ResourceType_Patient: - TestAndCopyTag(move, findResult, DICOM_TAG_PATIENT_ID); - break; - - case ResourceType_Study: - TestAndCopyTag(move, findResult, DICOM_TAG_STUDY_INSTANCE_UID); - break; - - case ResourceType_Series: - TestAndCopyTag(move, findResult, DICOM_TAG_STUDY_INSTANCE_UID); - TestAndCopyTag(move, findResult, DICOM_TAG_SERIES_INSTANCE_UID); - break; - - case ResourceType_Instance: - TestAndCopyTag(move, findResult, DICOM_TAG_STUDY_INSTANCE_UID); - TestAndCopyTag(move, findResult, DICOM_TAG_SERIES_INSTANCE_UID); - TestAndCopyTag(move, findResult, DICOM_TAG_SOP_INSTANCE_UID); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - MoveInternal(targetAet, level, move); - } - - - void DicomControlUserConnection::Move(const std::string& targetAet, - const DicomMap& findResult) - { - if (!findResult.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL)) - { - throw OrthancException(ErrorCode_InternalError); - } - - const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).GetContent(); - ResourceType level = StringToResourceType(tmp.c_str()); - - Move(targetAet, level, findResult); - } - - - void DicomControlUserConnection::MovePatient(const std::string& targetAet, - const std::string& patientId) - { - DicomMap query; - query.SetValue(DICOM_TAG_PATIENT_ID, patientId, false); - MoveInternal(targetAet, ResourceType_Patient, query); - } - - - void DicomControlUserConnection::MoveStudy(const std::string& targetAet, - const std::string& studyUid) - { - DicomMap query; - query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid, false); - MoveInternal(targetAet, ResourceType_Study, query); - } - - - void DicomControlUserConnection::MoveSeries(const std::string& targetAet, - const std::string& studyUid, - const std::string& seriesUid) - { - DicomMap query; - query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid, false); - query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid, false); - MoveInternal(targetAet, ResourceType_Series, query); - } - - - void DicomControlUserConnection::MoveInstance(const std::string& targetAet, - const std::string& studyUid, - const std::string& seriesUid, - const std::string& instanceUid) - { - DicomMap query; - query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid, false); - query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid, false); - query.SetValue(DICOM_TAG_SOP_INSTANCE_UID, instanceUid, false); - MoveInternal(targetAet, ResourceType_Instance, query); - } - - - void DicomControlUserConnection::FindWorklist(DicomFindAnswers& result, - ParsedDicomFile& query) - { - DcmDataset* dataset = query.GetDcmtkObject().getDataset(); - const char* sopClass = UID_FINDModalityWorklistInformationModel; - - FindInternal(result, dataset, sopClass, true, NULL); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomControlUserConnection.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1 -# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be set to 1 -#endif - -#include "DicomAssociationParameters.h" -#include "DicomFindAnswers.h" - -#include - -namespace Orthanc -{ - class DicomAssociation; // Forward declaration for PImpl design pattern - - class DicomControlUserConnection : public boost::noncopyable - { - private: - DicomAssociationParameters parameters_; - boost::shared_ptr association_; - - void SetupPresentationContexts(); - - void FindInternal(DicomFindAnswers& answers, - DcmDataset* dataset, - const char* sopClass, - bool isWorklist, - const char* level); - - void MoveInternal(const std::string& targetAet, - ResourceType level, - const DicomMap& fields); - - public: - DicomControlUserConnection(const DicomAssociationParameters& params); - - const DicomAssociationParameters& GetParameters() const - { - return parameters_; - } - - void Close(); - - bool Echo(); - - void Find(DicomFindAnswers& result, - ResourceType level, - const DicomMap& originalFields, - bool normalize); - - void Move(const std::string& targetAet, - ResourceType level, - const DicomMap& findResult); - - void Move(const std::string& targetAet, - const DicomMap& findResult); - - void MovePatient(const std::string& targetAet, - const std::string& patientId); - - void MoveStudy(const std::string& targetAet, - const std::string& studyUid); - - void MoveSeries(const std::string& targetAet, - const std::string& studyUid, - const std::string& seriesUid); - - void MoveInstance(const std::string& targetAet, - const std::string& studyUid, - const std::string& seriesUid, - const std::string& instanceUid); - - void FindWorklist(DicomFindAnswers& result, - ParsedDicomFile& query); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,209 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomFindAnswers.h" - -#include "../DicomParsing/FromDcmtkBridge.h" -#include "../OrthancException.h" - -#include -#include -#include - - -namespace Orthanc -{ - void DicomFindAnswers::AddAnswerInternal(ParsedDicomFile* answer) - { - std::unique_ptr protection(answer); - - if (isWorklist_) - { - // These lines are necessary when serving worklists, otherwise - // Orthanc does not behave as "wlmscpfs" - protection->Remove(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID); - protection->Remove(DICOM_TAG_SOP_INSTANCE_UID); - } - - protection->ChangeEncoding(encoding_); - - answers_.push_back(protection.release()); - } - - - DicomFindAnswers::DicomFindAnswers(bool isWorklist) : - encoding_(GetDefaultDicomEncoding()), - isWorklist_(isWorklist), - complete_(true) - { - } - - - void DicomFindAnswers::SetEncoding(Encoding encoding) - { - for (size_t i = 0; i < answers_.size(); i++) - { - assert(answers_[i] != NULL); - answers_[i]->ChangeEncoding(encoding); - } - - encoding_ = encoding; - } - - - void DicomFindAnswers::SetWorklist(bool isWorklist) - { - if (answers_.empty()) - { - isWorklist_ = isWorklist; - } - else - { - // This set of answers is not empty anymore, cannot change its type - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void DicomFindAnswers::Clear() - { - for (size_t i = 0; i < answers_.size(); i++) - { - assert(answers_[i] != NULL); - delete answers_[i]; - } - - answers_.clear(); - } - - - void DicomFindAnswers::Reserve(size_t size) - { - if (size > answers_.size()) - { - answers_.reserve(size); - } - } - - - void DicomFindAnswers::Add(const DicomMap& map) - { - // We use the permissive mode to be tolerant wrt. invalid DICOM - // files that contain some tags with out-of-range values (such - // tags are removed from the answers) - AddAnswerInternal(new ParsedDicomFile(map, encoding_, true /* permissive */)); - } - - - void DicomFindAnswers::Add(ParsedDicomFile& dicom) - { - AddAnswerInternal(dicom.Clone(true)); - } - - void DicomFindAnswers::Add(const void* dicom, - size_t size) - { - AddAnswerInternal(new ParsedDicomFile(dicom, size)); - } - - - ParsedDicomFile& DicomFindAnswers::GetAnswer(size_t index) const - { - if (index < answers_.size()) - { - return *answers_[index]; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - DcmDataset* DicomFindAnswers::ExtractDcmDataset(size_t index) const - { - // As "DicomFindAnswers" stores its content using class - // "ParsedDicomFile" (that internally uses "DcmFileFormat" from - // DCMTK), the dataset can contain tags that are reserved if - // storing the media on the disk, notably tag - // "MediaStorageSOPClassUID" (0002,0002). In this function, we - // remove all those tags whose group is below 0x0008. The - // resulting data set is clean for emission in the C-FIND SCP. - - // http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.html#sect_C.4.1.1.3 - // https://groups.google.com/d/msg/orthanc-users/D3kpPuX8yV0/_zgHOzkMEQAJ - - DcmDataset& source = *GetAnswer(index).GetDcmtkObject().getDataset(); - - std::unique_ptr target(new DcmDataset); - - for (unsigned long i = 0; i < source.card(); i++) - { - const DcmElement* element = source.getElement(i); - assert(element != NULL); - - if (element != NULL && - element->getTag().getGroup() >= 0x0008 && - element->getTag().getElement() != 0x0000) - { - target->insert(dynamic_cast(element->clone())); - } - } - - return target.release(); - } - - - void DicomFindAnswers::ToJson(Json::Value& target, - size_t index, - bool simplify) const - { - DicomToJsonFormat format = (simplify ? DicomToJsonFormat_Human : DicomToJsonFormat_Full); - GetAnswer(index).DatasetToJson(target, format, DicomToJsonFlags_None, 0); - } - - - void DicomFindAnswers::ToJson(Json::Value& target, - bool simplify) const - { - target = Json::arrayValue; - - for (size_t i = 0; i < GetSize(); i++) - { - Json::Value answer; - ToJson(answer, i, simplify); - target.append(answer); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomFindAnswers.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../DicomParsing/ParsedDicomFile.h" - -namespace Orthanc -{ - class DicomFindAnswers : public boost::noncopyable - { - private: - Encoding encoding_; - bool isWorklist_; - std::vector answers_; - bool complete_; - - void AddAnswerInternal(ParsedDicomFile* answer); - - public: - DicomFindAnswers(bool isWorklist); - - ~DicomFindAnswers() - { - Clear(); - } - - Encoding GetEncoding() const - { - return encoding_; - } - - void SetEncoding(Encoding encoding); - - void SetWorklist(bool isWorklist); - - bool IsWorklist() const - { - return isWorklist_; - } - - void Clear(); - - void Reserve(size_t index); - - void Add(const DicomMap& map); - - void Add(ParsedDicomFile& dicom); - - void Add(const void* dicom, - size_t size); - - size_t GetSize() const - { - return answers_.size(); - } - - ParsedDicomFile& GetAnswer(size_t index) const; - - DcmDataset* ExtractDcmDataset(size_t index) const; - - void ToJson(Json::Value& target, - bool simplify) const; - - void ToJson(Json::Value& target, - size_t index, - bool simplify) const; - - bool IsComplete() const - { - return complete_; - } - - void SetComplete(bool isComplete) - { - complete_ = isComplete; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,429 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomServer.h" - -#include "../Logging.h" -#include "../MultiThreading/RunnableWorkersPool.h" -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "Internals/CommandDispatcher.h" - -#include - -#if defined(__linux__) -#include -#endif - - -namespace Orthanc -{ - struct DicomServer::PImpl - { - boost::thread thread_; - T_ASC_Network *network_; - std::unique_ptr workers_; - }; - - - void DicomServer::ServerThread(DicomServer* server) - { - LOG(INFO) << "DICOM server started"; - - while (server->continue_) - { - /* receive an association and acknowledge or reject it. If the association was */ - /* acknowledged, offer corresponding services and invoke one or more if required. */ - std::unique_ptr dispatcher(Internals::AcceptAssociation(*server, server->pimpl_->network_)); - - try - { - if (dispatcher.get() != NULL) - { - server->pimpl_->workers_->Add(dispatcher.release()); - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception in the DICOM server thread: " << e.What(); - } - } - - LOG(INFO) << "DICOM server stopping"; - } - - - DicomServer::DicomServer() : - pimpl_(new PImpl), - aet_("ANY-SCP") - { - port_ = 104; - modalities_ = NULL; - findRequestHandlerFactory_ = NULL; - moveRequestHandlerFactory_ = NULL; - getRequestHandlerFactory_ = NULL; - storeRequestHandlerFactory_ = NULL; - worklistRequestHandlerFactory_ = NULL; - storageCommitmentFactory_ = NULL; - applicationEntityFilter_ = NULL; - checkCalledAet_ = true; - associationTimeout_ = 30; - continue_ = false; - } - - DicomServer::~DicomServer() - { - if (continue_) - { - LOG(ERROR) << "INTERNAL ERROR: DicomServer::Stop() should be invoked manually to avoid mess in the destruction order!"; - Stop(); - } - } - - void DicomServer::SetPortNumber(uint16_t port) - { - Stop(); - port_ = port; - } - - uint16_t DicomServer::GetPortNumber() const - { - return port_; - } - - void DicomServer::SetAssociationTimeout(uint32_t seconds) - { - LOG(INFO) << "Setting timeout for DICOM connections if Orthanc acts as SCP (server): " - << seconds << " seconds (0 = no timeout)"; - - Stop(); - associationTimeout_ = seconds; - } - - uint32_t DicomServer::GetAssociationTimeout() const - { - return associationTimeout_; - } - - - void DicomServer::SetCalledApplicationEntityTitleCheck(bool check) - { - Stop(); - checkCalledAet_ = check; - } - - bool DicomServer::HasCalledApplicationEntityTitleCheck() const - { - return checkCalledAet_; - } - - void DicomServer::SetApplicationEntityTitle(const std::string& aet) - { - if (aet.size() == 0) - { - throw OrthancException(ErrorCode_BadApplicationEntityTitle); - } - - if (aet.size() > 16) - { - throw OrthancException(ErrorCode_BadApplicationEntityTitle); - } - - for (size_t i = 0; i < aet.size(); i++) - { - if (!(aet[i] == '-' || - aet[i] == '_' || - isdigit(aet[i]) || - (aet[i] >= 'A' && aet[i] <= 'Z'))) - { - LOG(WARNING) << "For best interoperability, only upper case, alphanumeric characters should be present in AET: \"" << aet << "\""; - break; - } - } - - Stop(); - aet_ = aet; - } - - const std::string& DicomServer::GetApplicationEntityTitle() const - { - return aet_; - } - - void DicomServer::SetRemoteModalities(IRemoteModalities& modalities) - { - Stop(); - modalities_ = &modalities; - } - - DicomServer::IRemoteModalities& DicomServer::GetRemoteModalities() const - { - if (modalities_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return *modalities_; - } - } - - void DicomServer::SetFindRequestHandlerFactory(IFindRequestHandlerFactory& factory) - { - Stop(); - findRequestHandlerFactory_ = &factory; - } - - bool DicomServer::HasFindRequestHandlerFactory() const - { - return (findRequestHandlerFactory_ != NULL); - } - - IFindRequestHandlerFactory& DicomServer::GetFindRequestHandlerFactory() const - { - if (HasFindRequestHandlerFactory()) - { - return *findRequestHandlerFactory_; - } - else - { - throw OrthancException(ErrorCode_NoCFindHandler); - } - } - - void DicomServer::SetMoveRequestHandlerFactory(IMoveRequestHandlerFactory& factory) - { - Stop(); - moveRequestHandlerFactory_ = &factory; - } - - bool DicomServer::HasMoveRequestHandlerFactory() const - { - return (moveRequestHandlerFactory_ != NULL); - } - - IMoveRequestHandlerFactory& DicomServer::GetMoveRequestHandlerFactory() const - { - if (HasMoveRequestHandlerFactory()) - { - return *moveRequestHandlerFactory_; - } - else - { - throw OrthancException(ErrorCode_NoCMoveHandler); - } - } - - void DicomServer::SetGetRequestHandlerFactory(IGetRequestHandlerFactory& factory) - { - Stop(); - getRequestHandlerFactory_ = &factory; - } - - bool DicomServer::HasGetRequestHandlerFactory() const - { - return (getRequestHandlerFactory_ != NULL); - } - - IGetRequestHandlerFactory& DicomServer::GetGetRequestHandlerFactory() const - { - if (HasGetRequestHandlerFactory()) - { - return *getRequestHandlerFactory_; - } - else - { - throw OrthancException(ErrorCode_NoCGetHandler); - } - } - - void DicomServer::SetStoreRequestHandlerFactory(IStoreRequestHandlerFactory& factory) - { - Stop(); - storeRequestHandlerFactory_ = &factory; - } - - bool DicomServer::HasStoreRequestHandlerFactory() const - { - return (storeRequestHandlerFactory_ != NULL); - } - - IStoreRequestHandlerFactory& DicomServer::GetStoreRequestHandlerFactory() const - { - if (HasStoreRequestHandlerFactory()) - { - return *storeRequestHandlerFactory_; - } - else - { - throw OrthancException(ErrorCode_NoCStoreHandler); - } - } - - void DicomServer::SetWorklistRequestHandlerFactory(IWorklistRequestHandlerFactory& factory) - { - Stop(); - worklistRequestHandlerFactory_ = &factory; - } - - bool DicomServer::HasWorklistRequestHandlerFactory() const - { - return (worklistRequestHandlerFactory_ != NULL); - } - - IWorklistRequestHandlerFactory& DicomServer::GetWorklistRequestHandlerFactory() const - { - if (HasWorklistRequestHandlerFactory()) - { - return *worklistRequestHandlerFactory_; - } - else - { - throw OrthancException(ErrorCode_NoWorklistHandler); - } - } - - void DicomServer::SetStorageCommitmentRequestHandlerFactory(IStorageCommitmentRequestHandlerFactory& factory) - { - Stop(); - storageCommitmentFactory_ = &factory; - } - - bool DicomServer::HasStorageCommitmentRequestHandlerFactory() const - { - return (storageCommitmentFactory_ != NULL); - } - - IStorageCommitmentRequestHandlerFactory& DicomServer::GetStorageCommitmentRequestHandlerFactory() const - { - if (HasStorageCommitmentRequestHandlerFactory()) - { - return *storageCommitmentFactory_; - } - else - { - throw OrthancException(ErrorCode_NoStorageCommitmentHandler); - } - } - - void DicomServer::SetApplicationEntityFilter(IApplicationEntityFilter& factory) - { - Stop(); - applicationEntityFilter_ = &factory; - } - - bool DicomServer::HasApplicationEntityFilter() const - { - return (applicationEntityFilter_ != NULL); - } - - IApplicationEntityFilter& DicomServer::GetApplicationEntityFilter() const - { - if (HasApplicationEntityFilter()) - { - return *applicationEntityFilter_; - } - else - { - throw OrthancException(ErrorCode_NoApplicationEntityFilter); - } - } - - void DicomServer::Start() - { - if (modalities_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "No list of modalities was provided to the DICOM server"); - } - - Stop(); - - /* initialize network, i.e. create an instance of T_ASC_Network*. */ - OFCondition cond = ASC_initializeNetwork - (NET_ACCEPTOR, OFstatic_cast(int, port_), /*opt_acse_timeout*/ 30, &pimpl_->network_); - if (cond.bad()) - { - throw OrthancException(ErrorCode_DicomPortInUse, - " (port = " + boost::lexical_cast(port_) + ") cannot create network: " + std::string(cond.text())); - } - - continue_ = true; - pimpl_->workers_.reset(new RunnableWorkersPool(4)); // Use 4 workers - TODO as a parameter? - pimpl_->thread_ = boost::thread(ServerThread, this); - } - - - void DicomServer::Stop() - { - if (continue_) - { - continue_ = false; - - if (pimpl_->thread_.joinable()) - { - pimpl_->thread_.join(); - } - - pimpl_->workers_.reset(NULL); - - /* drop the network, i.e. free memory of T_ASC_Network* structure. This call */ - /* is the counterpart of ASC_initializeNetwork(...) which was called above. */ - OFCondition cond = ASC_dropNetwork(&pimpl_->network_); - if (cond.bad()) - { - LOG(ERROR) << "Error while dropping the network: " << cond.text(); - } - } - } - - - bool DicomServer::IsMyAETitle(const std::string& aet) const - { - if (modalities_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (!HasCalledApplicationEntityTitleCheck()) - { - // OK, no check on the AET. - return true; - } - else - { - return modalities_->IsSameAETitle(aet, GetApplicationEntityTitle()); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomServer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1 -# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be set to 1 -#endif - -#include "IFindRequestHandlerFactory.h" -#include "IMoveRequestHandlerFactory.h" -#include "IGetRequestHandlerFactory.h" -#include "IStoreRequestHandlerFactory.h" -#include "IWorklistRequestHandlerFactory.h" -#include "IStorageCommitmentRequestHandlerFactory.h" -#include "IApplicationEntityFilter.h" -#include "RemoteModalityParameters.h" - -#include -#include - - -namespace Orthanc -{ - class DicomServer : public boost::noncopyable - { - public: - // WARNING: The methods of this class must be thread-safe - class IRemoteModalities : public boost::noncopyable - { - public: - virtual ~IRemoteModalities() - { - } - - virtual bool IsSameAETitle(const std::string& aet1, - const std::string& aet2) = 0; - - virtual bool LookupAETitle(RemoteModalityParameters& modality, - const std::string& aet) = 0; - }; - - private: - struct PImpl; - boost::shared_ptr pimpl_; - - bool checkCalledAet_; - std::string aet_; - uint16_t port_; - bool continue_; - uint32_t associationTimeout_; - IRemoteModalities* modalities_; - IFindRequestHandlerFactory* findRequestHandlerFactory_; - IMoveRequestHandlerFactory* moveRequestHandlerFactory_; - IGetRequestHandlerFactory* getRequestHandlerFactory_; - IStoreRequestHandlerFactory* storeRequestHandlerFactory_; - IWorklistRequestHandlerFactory* worklistRequestHandlerFactory_; - IStorageCommitmentRequestHandlerFactory* storageCommitmentFactory_; - IApplicationEntityFilter* applicationEntityFilter_; - - static void ServerThread(DicomServer* server); - - public: - DicomServer(); - - ~DicomServer(); - - void SetPortNumber(uint16_t port); - uint16_t GetPortNumber() const; - - void SetAssociationTimeout(uint32_t seconds); - uint32_t GetAssociationTimeout() const; - - void SetCalledApplicationEntityTitleCheck(bool check); - bool HasCalledApplicationEntityTitleCheck() const; - - void SetApplicationEntityTitle(const std::string& aet); - const std::string& GetApplicationEntityTitle() const; - - void SetRemoteModalities(IRemoteModalities& modalities); - IRemoteModalities& GetRemoteModalities() const; - - void SetFindRequestHandlerFactory(IFindRequestHandlerFactory& handler); - bool HasFindRequestHandlerFactory() const; - IFindRequestHandlerFactory& GetFindRequestHandlerFactory() const; - - void SetMoveRequestHandlerFactory(IMoveRequestHandlerFactory& handler); - bool HasMoveRequestHandlerFactory() const; - IMoveRequestHandlerFactory& GetMoveRequestHandlerFactory() const; - - void SetGetRequestHandlerFactory(IGetRequestHandlerFactory& handler); - bool HasGetRequestHandlerFactory() const; - IGetRequestHandlerFactory& GetGetRequestHandlerFactory() const; - - void SetStoreRequestHandlerFactory(IStoreRequestHandlerFactory& handler); - bool HasStoreRequestHandlerFactory() const; - IStoreRequestHandlerFactory& GetStoreRequestHandlerFactory() const; - - void SetWorklistRequestHandlerFactory(IWorklistRequestHandlerFactory& handler); - bool HasWorklistRequestHandlerFactory() const; - IWorklistRequestHandlerFactory& GetWorklistRequestHandlerFactory() const; - - void SetStorageCommitmentRequestHandlerFactory(IStorageCommitmentRequestHandlerFactory& handler); - bool HasStorageCommitmentRequestHandlerFactory() const; - IStorageCommitmentRequestHandlerFactory& GetStorageCommitmentRequestHandlerFactory() const; - - void SetApplicationEntityFilter(IApplicationEntityFilter& handler); - bool HasApplicationEntityFilter() const; - IApplicationEntityFilter& GetApplicationEntityFilter() const; - - void Start(); - - void Stop(); - - bool IsMyAETitle(const std::string& aet) const; - }; - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,527 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomStoreUserConnection.h" - -#include "../DicomParsing/FromDcmtkBridge.h" -#include "../DicomParsing/ParsedDicomFile.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "DicomAssociation.h" - -#include - - -namespace Orthanc -{ - bool DicomStoreUserConnection::ProposeStorageClass(const std::string& sopClassUid, - const std::set& syntaxes) - { - // Default transfer syntax for DICOM - const bool addLittleEndianImplicit = ( - proposeUncompressedSyntaxes_ && - syntaxes.find(DicomTransferSyntax_LittleEndianImplicit) == syntaxes.end()); - - const bool addLittleEndianExplicit = ( - proposeUncompressedSyntaxes_ && - syntaxes.find(DicomTransferSyntax_LittleEndianExplicit) == syntaxes.end()); - - const bool addBigEndianExplicit = ( - proposeUncompressedSyntaxes_ && - proposeRetiredBigEndian_ && - syntaxes.find(DicomTransferSyntax_BigEndianExplicit) == syntaxes.end()); - - size_t requiredCount = syntaxes.size(); - if (addLittleEndianImplicit) - { - requiredCount += 1; - } - - if (addLittleEndianExplicit || - addBigEndianExplicit) - { - requiredCount += 1; - } - - if (association_->GetRemainingPropositions() <= requiredCount) - { - return false; // Not enough room - } - else - { - for (std::set::const_iterator - it = syntaxes.begin(); it != syntaxes.end(); ++it) - { - association_->ProposePresentationContext(sopClassUid, *it); - proposedOriginalClasses_.insert(std::make_pair(sopClassUid, *it)); - } - - if (addLittleEndianImplicit) - { - association_->ProposePresentationContext(sopClassUid, DicomTransferSyntax_LittleEndianImplicit); - proposedOriginalClasses_.insert(std::make_pair(sopClassUid, DicomTransferSyntax_LittleEndianImplicit)); - } - - if (addLittleEndianExplicit || - addBigEndianExplicit) - { - std::set uncompressed; - - if (addLittleEndianExplicit) - { - uncompressed.insert(DicomTransferSyntax_LittleEndianExplicit); - } - - if (addBigEndianExplicit) - { - uncompressed.insert(DicomTransferSyntax_BigEndianExplicit); - } - - association_->ProposePresentationContext(sopClassUid, uncompressed); - - assert(!uncompressed.empty()); - if (addLittleEndianExplicit ^ addBigEndianExplicit) - { - // Only one transfer syntax was proposed for this presentation context - assert(uncompressed.size() == 1); - proposedOriginalClasses_.insert(std::make_pair(sopClassUid, *uncompressed.begin())); - } - } - - return true; - } - } - - - bool DicomStoreUserConnection::LookupPresentationContext( - uint8_t& presentationContextId, - const std::string& sopClassUid, - DicomTransferSyntax transferSyntax) - { - typedef std::map PresentationContexts; - - PresentationContexts pc; - if (association_->IsOpen() && - association_->LookupAcceptedPresentationContext(pc, sopClassUid)) - { - PresentationContexts::const_iterator found = pc.find(transferSyntax); - if (found != pc.end()) - { - presentationContextId = found->second; - return true; - } - } - - return false; - } - - - DicomStoreUserConnection::DicomStoreUserConnection( - const DicomAssociationParameters& params) : - parameters_(params), - association_(new DicomAssociation), - proposeCommonClasses_(true), - proposeUncompressedSyntaxes_(true), - proposeRetiredBigEndian_(false) - { - } - - - void DicomStoreUserConnection::RegisterStorageClass(const std::string& sopClassUid, - DicomTransferSyntax syntax) - { - RegisteredClasses::iterator found = registeredClasses_.find(sopClassUid); - - if (found == registeredClasses_.end()) - { - std::set ts; - ts.insert(syntax); - registeredClasses_[sopClassUid] = ts; - } - else - { - found->second.insert(syntax); - } - } - - - void DicomStoreUserConnection::LookupParameters(std::string& sopClassUid, - std::string& sopInstanceUid, - DicomTransferSyntax& transferSyntax, - DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - OFString a, b; - if (!dicom.getDataset()->findAndGetOFString(DCM_SOPClassUID, a).good() || - !dicom.getDataset()->findAndGetOFString(DCM_SOPInstanceUID, b).good()) - { - throw OrthancException(ErrorCode_NoSopClassOrInstance, - "Unable to determine the SOP class/instance for C-STORE with AET " + - parameters_.GetRemoteModality().GetApplicationEntityTitle()); - } - - sopClassUid.assign(a.c_str()); - sopInstanceUid.assign(b.c_str()); - - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transferSyntax, dicom)) - { - throw OrthancException(ErrorCode_InternalError, - "Unknown transfer syntax from DCMTK"); - } - } - - - bool DicomStoreUserConnection::NegotiatePresentationContext( - uint8_t& presentationContextId, - const std::string& sopClassUid, - DicomTransferSyntax transferSyntax) - { - /** - * Step 1: Check whether this presentation context is already - * available in the previously negotiated assocation. - **/ - - if (LookupPresentationContext(presentationContextId, sopClassUid, transferSyntax)) - { - return true; - } - - // The association must be re-negotiated - if (association_->IsOpen()) - { - LOG(INFO) << "Re-negotiating DICOM association with " - << parameters_.GetRemoteModality().GetApplicationEntityTitle(); - - if (proposedOriginalClasses_.find(std::make_pair(sopClassUid, transferSyntax)) != - proposedOriginalClasses_.end()) - { - LOG(INFO) << "The remote modality has already rejected SOP class UID \"" - << sopClassUid << "\" with transfer syntax \"" - << GetTransferSyntaxUid(transferSyntax) << "\", don't renegotiate"; - return false; - } - } - - association_->ClearPresentationContexts(); - proposedOriginalClasses_.clear(); - RegisterStorageClass(sopClassUid, transferSyntax); // (*) - - - /** - * Step 2: Propose at least the mandatory SOP class. - **/ - - { - RegisteredClasses::const_iterator mandatory = registeredClasses_.find(sopClassUid); - - if (mandatory == registeredClasses_.end() || - mandatory->second.find(transferSyntax) == mandatory->second.end()) - { - // Should never fail because of (*) - throw OrthancException(ErrorCode_InternalError); - } - - if (!ProposeStorageClass(sopClassUid, mandatory->second)) - { - // Should never happen in real life: There are no more than - // 128 transfer syntaxes in DICOM! - throw OrthancException(ErrorCode_InternalError, - "Too many transfer syntaxes for SOP class UID: " + sopClassUid); - } - } - - - /** - * Step 3: Propose all the previously spotted SOP classes, as - * registered through the "RegisterStorageClass()" method. - **/ - - for (RegisteredClasses::const_iterator it = registeredClasses_.begin(); - it != registeredClasses_.end(); ++it) - { - if (it->first != sopClassUid) - { - ProposeStorageClass(it->first, it->second); - } - } - - - /** - * Step 4: As long as there is room left in the proposed - * presentation contexts, propose the uncompressed transfer syntaxes - * for the most common SOP classes, as can be found in the - * "dcmShortSCUStorageSOPClassUIDs" array from DCMTK. The - * preferred transfer syntax is "LittleEndianImplicit". - **/ - - if (proposeCommonClasses_) - { - // The method "ProposeStorageClass()" will automatically add - // "LittleEndianImplicit" - std::set ts; - - for (int i = 0; i < numberOfDcmShortSCUStorageSOPClassUIDs; i++) - { - std::string c(dcmShortSCUStorageSOPClassUIDs[i]); - - if (c != sopClassUid && - registeredClasses_.find(c) == registeredClasses_.end()) - { - ProposeStorageClass(c, ts); - } - } - } - - - /** - * Step 5: Open the association, and check whether the pair (SOP - * class UID, transfer syntax) was accepted by the remote host. - **/ - - association_->Open(parameters_); - return LookupPresentationContext(presentationContextId, sopClassUid, transferSyntax); - } - - - void DicomStoreUserConnection::Store(std::string& sopClassUid, - std::string& sopInstanceUid, - DcmFileFormat& dicom, - bool hasMoveOriginator, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID) - { - DicomTransferSyntax transferSyntax; - LookupParameters(sopClassUid, sopInstanceUid, transferSyntax, dicom); - - uint8_t presID; - if (!NegotiatePresentationContext(presID, sopClassUid, transferSyntax)) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "No valid presentation context was negotiated for " - "SOP class UID [" + sopClassUid + "] and transfer " - "syntax [" + GetTransferSyntaxUid(transferSyntax) + "] " - "while sending to modality [" + - parameters_.GetRemoteModality().GetApplicationEntityTitle() + "]"); - } - - // Prepare the transmission of data - T_DIMSE_C_StoreRQ request; - memset(&request, 0, sizeof(request)); - request.MessageID = association_->GetDcmtkAssociation().nextMsgID++; - strncpy(request.AffectedSOPClassUID, sopClassUid.c_str(), DIC_UI_LEN); - request.Priority = DIMSE_PRIORITY_MEDIUM; - request.DataSetType = DIMSE_DATASET_PRESENT; - strncpy(request.AffectedSOPInstanceUID, sopInstanceUid.c_str(), DIC_UI_LEN); - - if (hasMoveOriginator) - { - strncpy(request.MoveOriginatorApplicationEntityTitle, - moveOriginatorAET.c_str(), DIC_AE_LEN); - request.opts = O_STORE_MOVEORIGINATORAETITLE; - - request.MoveOriginatorID = moveOriginatorID; // The type DIC_US is an alias for uint16_t - request.opts |= O_STORE_MOVEORIGINATORID; - } - - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - // Finally conduct transmission of data - T_DIMSE_C_StoreRSP response; - DcmDataset* statusDetail = NULL; - DicomAssociation::CheckCondition( - DIMSE_storeUser(&association_->GetDcmtkAssociation(), presID, &request, - NULL, dicom.getDataset(), /*progressCallback*/ NULL, NULL, - /*opt_blockMode*/ (GetParameters().HasTimeout() ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ GetParameters().GetTimeout(), - &response, &statusDetail, NULL), - GetParameters(), "C-STORE"); - - if (statusDetail != NULL) - { - delete statusDetail; - } - - /** - * New in Orthanc 1.6.0: Deal with failures during C-STORE. - * http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_B.2.3.html#table_B.2-1 - **/ - - if (response.DimseStatus != 0x0000 && // Success - response.DimseStatus != 0xB000 && // Warning - Coercion of Data Elements - response.DimseStatus != 0xB007 && // Warning - Data Set does not match SOP Class - response.DimseStatus != 0xB006) // Warning - Elements Discarded - { - char buf[16]; - sprintf(buf, "%04X", response.DimseStatus); - throw OrthancException(ErrorCode_NetworkProtocol, - "C-STORE SCU to AET \"" + - GetParameters().GetRemoteModality().GetApplicationEntityTitle() + - "\" has failed with DIMSE status 0x" + buf); - } - } - - - void DicomStoreUserConnection::Store(std::string& sopClassUid, - std::string& sopInstanceUid, - const void* buffer, - size_t size, - bool hasMoveOriginator, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID) - { - std::unique_ptr dicom( - FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size)); - - if (dicom.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - Store(sopClassUid, sopInstanceUid, *dicom, hasMoveOriginator, moveOriginatorAET, moveOriginatorID); - } - - - void DicomStoreUserConnection::LookupTranscoding(std::set& acceptedSyntaxes, - const std::string& sopClassUid, - DicomTransferSyntax sourceSyntax) - { - acceptedSyntaxes.clear(); - - // Make sure a negotiation has already occurred for this transfer - // syntax. We don't use the return code: Transcoding is possible - // even if the "sourceSyntax" is not supported. - uint8_t presID; - NegotiatePresentationContext(presID, sopClassUid, sourceSyntax); - - std::map contexts; - if (association_->LookupAcceptedPresentationContext(contexts, sopClassUid)) - { - for (std::map::const_iterator - it = contexts.begin(); it != contexts.end(); ++it) - { - acceptedSyntaxes.insert(it->first); - } - } - } - - - void DicomStoreUserConnection::Transcode(std::string& sopClassUid /* out */, - std::string& sopInstanceUid /* out */, - IDicomTranscoder& transcoder, - const void* buffer, - size_t size, - bool hasMoveOriginator, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID) - { - std::unique_ptr dicom(FromDcmtkBridge::LoadFromMemoryBuffer(buffer, size)); - if (dicom.get() == NULL || - dicom->getDataset() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - DicomTransferSyntax inputSyntax; - LookupParameters(sopClassUid, sopInstanceUid, inputSyntax, *dicom); - - std::set accepted; - LookupTranscoding(accepted, sopClassUid, inputSyntax); - - if (accepted.find(inputSyntax) != accepted.end()) - { - // No need for transcoding - Store(sopClassUid, sopInstanceUid, *dicom, - hasMoveOriginator, moveOriginatorAET, moveOriginatorID); - } - else - { - // Transcoding is needed - std::set uncompressedSyntaxes; - - if (accepted.find(DicomTransferSyntax_LittleEndianImplicit) != accepted.end()) - { - uncompressedSyntaxes.insert(DicomTransferSyntax_LittleEndianImplicit); - } - - if (accepted.find(DicomTransferSyntax_LittleEndianExplicit) != accepted.end()) - { - uncompressedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); - } - - if (accepted.find(DicomTransferSyntax_BigEndianExplicit) != accepted.end()) - { - uncompressedSyntaxes.insert(DicomTransferSyntax_BigEndianExplicit); - } - - IDicomTranscoder::DicomImage source; - source.AcquireParsed(dicom.release()); - source.SetExternalBuffer(buffer, size); - - const std::string sourceUid = IDicomTranscoder::GetSopInstanceUid(source.GetParsed()); - - IDicomTranscoder::DicomImage transcoded; - if (transcoder.Transcode(transcoded, source, uncompressedSyntaxes, false)) - { - if (sourceUid != IDicomTranscoder::GetSopInstanceUid(transcoded.GetParsed())) - { - throw OrthancException(ErrorCode_Plugin, "The transcoder has changed the SOP " - "instance UID while transcoding to an uncompressed transfer syntax"); - } - else - { - DicomTransferSyntax transcodedSyntax; - - // Sanity check - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(transcodedSyntax, transcoded.GetParsed()) || - accepted.find(transcodedSyntax) == accepted.end()) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - Store(sopClassUid, sopInstanceUid, transcoded.GetParsed(), - hasMoveOriginator, moveOriginatorAET, moveOriginatorID); - } - } - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/DicomStoreUserConnection.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_DCMTK_TRANSCODING) -# error Macro ORTHANC_ENABLE_DCMTK_TRANSCODING must be defined to use this file -#endif - -#include "DicomAssociationParameters.h" - -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 -# include "../DicomParsing/IDicomTranscoder.h" -#endif - -#include -#include -#include -#include // For uint8_t - - -class DcmFileFormat; - -namespace Orthanc -{ - /** - - Orthanc < 1.7.0: - - Input | Output - -------------+--------------------------------------------- - Compressed | Same transfer syntax - Uncompressed | Same transfer syntax, or other uncompressed - - Orthanc >= 1.7.0: - - Input | Output - -------------+--------------------------------------------- - Compressed | Same transfer syntax, or uncompressed - Uncompressed | Same transfer syntax, or other uncompressed - - **/ - - class DicomAssociation; // Forward declaration for PImpl design pattern - - class DicomStoreUserConnection : public boost::noncopyable - { - private: - typedef std::map > RegisteredClasses; - - // "ProposedOriginalClasses" keeps track of the storage classes - // that were proposed with a single transfer syntax - typedef std::set< std::pair > ProposedOriginalClasses; - - DicomAssociationParameters parameters_; - boost::shared_ptr association_; // "shared_ptr" is for PImpl - RegisteredClasses registeredClasses_; - ProposedOriginalClasses proposedOriginalClasses_; - bool proposeCommonClasses_; - bool proposeUncompressedSyntaxes_; - bool proposeRetiredBigEndian_; - - // Return "false" if there is not enough room remaining in the association - bool ProposeStorageClass(const std::string& sopClassUid, - const std::set& syntaxes); - - bool LookupPresentationContext(uint8_t& presentationContextId, - const std::string& sopClassUid, - DicomTransferSyntax transferSyntax); - - bool NegotiatePresentationContext(uint8_t& presentationContextId, - const std::string& sopClassUid, - DicomTransferSyntax transferSyntax); - - void LookupTranscoding(std::set& acceptedSyntaxes, - const std::string& sopClassUid, - DicomTransferSyntax sourceSyntax); - - public: - DicomStoreUserConnection(const DicomAssociationParameters& params); - - const DicomAssociationParameters& GetParameters() const - { - return parameters_; - } - - void SetCommonClassesProposed(bool proposed) - { - proposeCommonClasses_ = proposed; - } - - bool IsCommonClassesProposed() const - { - return proposeCommonClasses_; - } - - void SetUncompressedSyntaxesProposed(bool proposed) - { - proposeUncompressedSyntaxes_ = proposed; - } - - bool IsUncompressedSyntaxesProposed() const - { - return proposeUncompressedSyntaxes_; - } - - void SetRetiredBigEndianProposed(bool propose) - { - proposeRetiredBigEndian_ = propose; - } - - bool IsRetiredBigEndianProposed() const - { - return proposeRetiredBigEndian_; - } - - void RegisterStorageClass(const std::string& sopClassUid, - DicomTransferSyntax syntax); - - void Store(std::string& sopClassUid, - std::string& sopInstanceUid, - DcmFileFormat& dicom, - bool hasMoveOriginator, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID); - - void Store(std::string& sopClassUid, - std::string& sopInstanceUid, - const void* buffer, - size_t size, - bool hasMoveOriginator, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID); - - void LookupParameters(std::string& sopClassUid, - std::string& sopInstanceUid, - DicomTransferSyntax& transferSyntax, - DcmFileFormat& dicom); - - void Transcode(std::string& sopClassUid /* out */, - std::string& sopInstanceUid /* out */, - IDicomTranscoder& transcoder, - const void* buffer, - size_t size, - bool hasMoveOriginator, - const std::string& moveOriginatorAET, - uint16_t moveOriginatorID); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IApplicationEntityFilter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IApplicationEntityFilter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IApplicationEntityFilter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IApplicationEntityFilter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include - -namespace Orthanc -{ - class IApplicationEntityFilter : public boost::noncopyable - { - public: - virtual ~IApplicationEntityFilter() - { - } - - virtual bool IsAllowedConnection(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) = 0; - - virtual bool IsAllowedRequest(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - DicomRequestType type) = 0; - - virtual bool IsAllowedTransferSyntax(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - TransferSyntax syntax) = 0; - - virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandlerFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandlerFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandlerFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandlerFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IFindRequestHandler.h" - -namespace Orthanc -{ - class IFindRequestHandlerFactory : public boost::noncopyable - { - public: - virtual ~IFindRequestHandlerFactory() - { - } - - virtual IFindRequestHandler* ConstructFindRequestHandler() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IFindRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomFindAnswers.h" - -#include - -namespace Orthanc -{ - class IFindRequestHandler : public boost::noncopyable - { - public: - virtual ~IFindRequestHandler() - { - } - - virtual void Handle(DicomFindAnswers& answers, - const DicomMap& input, - const std::list& sequencesToReturn, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandlerFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandlerFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandlerFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandlerFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IGetRequestHandler.h" - -namespace Orthanc -{ - class IGetRequestHandlerFactory : public boost::noncopyable - { - public: - virtual ~IGetRequestHandlerFactory() - { - } - - virtual IGetRequestHandler* ConstructGetRequestHandler() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IGetRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include - -#include "../DicomFormat/DicomMap.h" - -#include - - -namespace Orthanc -{ - class IGetRequestHandler : boost::noncopyable - { - public: - enum Status - { - Status_Success, - Status_Failure, - Status_Warning - }; - - virtual ~IGetRequestHandler() - { - } - - virtual bool Handle(const DicomMap& input, - const std::string& originatorIp, - const std::string& originatorAet, - const std::string& calledAet, - uint32_t timeout) = 0; - - virtual unsigned int GetSubOperationCount() const = 0; - - virtual Status DoNext(T_ASC_Association *) = 0; - - virtual unsigned int GetRemainingCount() const = 0; - - virtual unsigned int GetCompletedCount() const = 0; - - virtual unsigned int GetWarningCount() const = 0; - - virtual unsigned int GetFailedCount() const = 0; - - virtual const std::string& GetFailedUids() const = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandlerFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandlerFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandlerFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandlerFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IMoveRequestHandler.h" - -namespace Orthanc -{ - class IMoveRequestHandlerFactory : public boost::noncopyable - { - public: - virtual ~IMoveRequestHandlerFactory() - { - } - - virtual IMoveRequestHandler* ConstructMoveRequestHandler() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IMoveRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../DicomFormat/DicomMap.h" - -#include -#include - - -namespace Orthanc -{ - class IMoveRequestIterator : public boost::noncopyable - { - public: - enum Status - { - Status_Success, - Status_Failure, - Status_Warning - }; - - virtual ~IMoveRequestIterator() - { - } - - virtual unsigned int GetSubOperationCount() const = 0; - - virtual Status DoNext() = 0; - }; - - - class IMoveRequestHandler - { - public: - virtual ~IMoveRequestHandler() - { - } - - virtual IMoveRequestIterator* Handle(const std::string& targetAet, - const DicomMap& input, - const std::string& originatorIp, - const std::string& originatorAet, - const std::string& calledAet, - uint16_t originatorId) = 0; - }; - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1346 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: DCMTK 3.6.0 - Module: http://dicom.offis.de/dcmtk.php.en - -Copyright (C) 1994-2011, OFFIS e.V. -All rights reserved. - -This software and supporting documentation were developed by - - OFFIS e.V. - R&D Division Health - Escherweg 2 - 26121 Oldenburg, Germany - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -- Neither the name of OFFIS nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 COPYRIGHT -HOLDER OR CONTRIBUTORS 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. - -=========================================================================*/ - - -#include "../../PrecompiledHeaders.h" -#include "CommandDispatcher.h" - -#if !defined(DCMTK_VERSION_NUMBER) -# error The macro DCMTK_VERSION_NUMBER must be defined -#endif - -#include "FindScp.h" -#include "StoreScp.h" -#include "MoveScp.h" -#include "GetScp.h" -#include "../../Compatibility.h" -#include "../../Toolbox.h" -#include "../../Logging.h" -#include "../../OrthancException.h" - -#include /* for storage commitment */ -#include /* for class DcmSequenceOfItems */ -#include /* for variable dcmAllStorageSOPClassUIDs */ -#include /* for class DcmAssociationConfiguration */ - -#include - - static OFBool opt_rejectWithoutImplementationUID = OFFalse; - - - -static DUL_PRESENTATIONCONTEXT * -findPresentationContextID(LST_HEAD * head, - T_ASC_PresentationContextID presentationContextID) -{ - DUL_PRESENTATIONCONTEXT *pc; - LST_HEAD **l; - OFBool found = OFFalse; - - if (head == NULL) - return NULL; - - l = &head; - if (*l == NULL) - return NULL; - - pc = OFstatic_cast(DUL_PRESENTATIONCONTEXT *, LST_Head(l)); - (void)LST_Position(l, OFstatic_cast(LST_NODE *, pc)); - - while (pc && !found) { - if (pc->presentationContextID == presentationContextID) { - found = OFTrue; - } else { - pc = OFstatic_cast(DUL_PRESENTATIONCONTEXT *, LST_Next(l)); - } - } - return pc; -} - - -/** accept all presenstation contexts for unknown SOP classes, - * i.e. UIDs appearing in the list of abstract syntaxes - * where no corresponding name is defined in the UID dictionary. - * @param params pointer to association parameters structure - * @param transferSyntax transfer syntax to accept - * @param acceptedRole SCU/SCP role to accept - */ -static OFCondition acceptUnknownContextsWithTransferSyntax( - T_ASC_Parameters * params, - const char* transferSyntax, - T_ASC_SC_ROLE acceptedRole) -{ - OFCondition cond = EC_Normal; - int n, i, k; - DUL_PRESENTATIONCONTEXT *dpc; - T_ASC_PresentationContext pc; - OFBool accepted = OFFalse; - OFBool abstractOK = OFFalse; - - n = ASC_countPresentationContexts(params); - for (i = 0; i < n; i++) - { - cond = ASC_getPresentationContext(params, i, &pc); - if (cond.bad()) return cond; - abstractOK = OFFalse; - accepted = OFFalse; - - if (dcmFindNameOfUID(pc.abstractSyntax) == NULL) - { - abstractOK = OFTrue; - - /* check the transfer syntax */ - for (k = 0; (k < OFstatic_cast(int, pc.transferSyntaxCount)) && !accepted; k++) - { - if (strcmp(pc.proposedTransferSyntaxes[k], transferSyntax) == 0) - { - accepted = OFTrue; - } - } - } - - if (accepted) - { - cond = ASC_acceptPresentationContext( - params, pc.presentationContextID, - transferSyntax, acceptedRole); - if (cond.bad()) return cond; - } else { - T_ASC_P_ResultReason reason; - - /* do not refuse if already accepted */ - dpc = findPresentationContextID(params->DULparams.acceptedPresentationContext, - pc.presentationContextID); - if ((dpc == NULL) || ((dpc != NULL) && (dpc->result != ASC_P_ACCEPTANCE))) - { - - if (abstractOK) { - reason = ASC_P_TRANSFERSYNTAXESNOTSUPPORTED; - } else { - reason = ASC_P_ABSTRACTSYNTAXNOTSUPPORTED; - } - /* - * If previously this presentation context was refused - * because of bad transfer syntax let it stay that way. - */ - if ((dpc != NULL) && (dpc->result == ASC_P_TRANSFERSYNTAXESNOTSUPPORTED)) - reason = ASC_P_TRANSFERSYNTAXESNOTSUPPORTED; - - cond = ASC_refusePresentationContext(params, pc.presentationContextID, reason); - if (cond.bad()) return cond; - } - } - } - return EC_Normal; -} - - -/** accept all presenstation contexts for unknown SOP classes, - * i.e. UIDs appearing in the list of abstract syntaxes - * where no corresponding name is defined in the UID dictionary. - * This method is passed a list of "preferred" transfer syntaxes. - * @param params pointer to association parameters structure - * @param transferSyntax transfer syntax to accept - * @param acceptedRole SCU/SCP role to accept - */ -static OFCondition acceptUnknownContextsWithPreferredTransferSyntaxes( - T_ASC_Parameters * params, - const char* transferSyntaxes[], int transferSyntaxCount, - T_ASC_SC_ROLE acceptedRole) -{ - OFCondition cond = EC_Normal; - /* - ** Accept in the order "least wanted" to "most wanted" transfer - ** syntax. Accepting a transfer syntax will override previously - ** accepted transfer syntaxes. - */ - for (int i = transferSyntaxCount - 1; i >= 0; i--) - { - cond = acceptUnknownContextsWithTransferSyntax(params, transferSyntaxes[i], acceptedRole); - if (cond.bad()) return cond; - } - return cond; -} - - - -namespace Orthanc -{ - namespace Internals - { - OFCondition AssociationCleanup(T_ASC_Association *assoc) - { - OFCondition cond = ASC_dropSCPAssociation(assoc); - if (cond.bad()) - { - LOG(FATAL) << cond.text(); - return cond; - } - - cond = ASC_destroyAssociation(&assoc); - if (cond.bad()) - { - LOG(FATAL) << cond.text(); - return cond; - } - - return cond; - } - - - - CommandDispatcher* AcceptAssociation(const DicomServer& server, T_ASC_Network *net) - { - DcmAssociationConfiguration asccfg; - char buf[BUFSIZ]; - T_ASC_Association *assoc; - OFCondition cond; - OFString sprofile; - OFString temp_str; - - cond = ASC_receiveAssociation(net, &assoc, - /*opt_maxPDU*/ ASC_DEFAULTMAXPDU, - NULL, NULL, - /*opt_secureConnection*/ OFFalse, - DUL_NOBLOCK, 1); - - if (cond == DUL_NOASSOCIATIONREQUEST) - { - // Timeout - AssociationCleanup(assoc); - return NULL; - } - - // if some kind of error occured, take care of it - if (cond.bad()) - { - LOG(ERROR) << "Receiving Association failed: " << cond.text(); - // no matter what kind of error occurred, we need to do a cleanup - AssociationCleanup(assoc); - return NULL; - } - - // Retrieve the AET and the IP address of the remote modality - std::string remoteAet; - std::string remoteIp; - std::string calledAet; - - { - DIC_AE remoteAet_C; - DIC_AE calledAet_C; - DIC_AE remoteIp_C; - DIC_AE calledIP_C; - - if ( -#if DCMTK_VERSION_NUMBER >= 364 - ASC_getAPTitles(assoc->params, remoteAet_C, sizeof(remoteAet_C), calledAet_C, sizeof(calledAet_C), NULL, 0).bad() || - ASC_getPresentationAddresses(assoc->params, remoteIp_C, sizeof(remoteIp_C), calledIP_C, sizeof(calledIP_C)).bad() -#else - ASC_getAPTitles(assoc->params, remoteAet_C, calledAet_C, NULL).bad() || - ASC_getPresentationAddresses(assoc->params, remoteIp_C, calledIP_C).bad() -#endif - ) - { - T_ASC_RejectParameters rej = - { - ASC_RESULT_REJECTEDPERMANENT, - ASC_SOURCE_SERVICEUSER, - ASC_REASON_SU_NOREASON - }; - ASC_rejectAssociation(assoc, &rej); - AssociationCleanup(assoc); - return NULL; - } - - remoteIp = std::string(/*OFSTRING_GUARD*/(remoteIp_C)); - remoteAet = std::string(/*OFSTRING_GUARD*/(remoteAet_C)); - calledAet = (/*OFSTRING_GUARD*/(calledAet_C)); - } - - LOG(INFO) << "Association Received from AET " << remoteAet - << " on IP " << remoteIp; - - - { - /* accept the abstract syntaxes for C-ECHO, C-FIND, C-MOVE, - and storage commitment, if presented */ - - std::vector genericTransferSyntaxes; - genericTransferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax); - genericTransferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax); - genericTransferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax); - - std::vector knownAbstractSyntaxes; - - // For C-ECHO (always enabled since Orthanc 1.6.0; in earlier - // versions, only enabled if C-STORE was also enabled) - knownAbstractSyntaxes.push_back(UID_VerificationSOPClass); - - // For C-FIND - if (server.HasFindRequestHandlerFactory()) - { - knownAbstractSyntaxes.push_back(UID_FINDPatientRootQueryRetrieveInformationModel); - knownAbstractSyntaxes.push_back(UID_FINDStudyRootQueryRetrieveInformationModel); - } - - if (server.HasWorklistRequestHandlerFactory()) - { - knownAbstractSyntaxes.push_back(UID_FINDModalityWorklistInformationModel); - } - - // For C-MOVE - if (server.HasMoveRequestHandlerFactory()) - { - knownAbstractSyntaxes.push_back(UID_MOVEStudyRootQueryRetrieveInformationModel); - knownAbstractSyntaxes.push_back(UID_MOVEPatientRootQueryRetrieveInformationModel); - } - - // For C-GET - if (server.HasGetRequestHandlerFactory()) - { - knownAbstractSyntaxes.push_back(UID_GETStudyRootQueryRetrieveInformationModel); - knownAbstractSyntaxes.push_back(UID_GETPatientRootQueryRetrieveInformationModel); - } - - cond = ASC_acceptContextsWithPreferredTransferSyntaxes( - assoc->params, - &knownAbstractSyntaxes[0], knownAbstractSyntaxes.size(), - &genericTransferSyntaxes[0], genericTransferSyntaxes.size()); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - AssociationCleanup(assoc); - return NULL; - } - - - /* storage commitment support, new in Orthanc 1.6.0 */ - if (server.HasStorageCommitmentRequestHandlerFactory()) - { - /** - * "ASC_SC_ROLE_SCUSCP": The "SCU" role is needed to accept - * remote storage commitment requests, and the "SCP" role is - * needed to receive storage commitments answers. - **/ - const char* as[1] = { UID_StorageCommitmentPushModelSOPClass }; - cond = ASC_acceptContextsWithPreferredTransferSyntaxes( - assoc->params, as, 1, - &genericTransferSyntaxes[0], genericTransferSyntaxes.size(), ASC_SC_ROLE_SCUSCP); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - AssociationCleanup(assoc); - return NULL; - } - } - } - - - { - /* accept the abstract syntaxes for C-STORE, if presented */ - - std::vector storageTransferSyntaxes; - - // This is the list of the transfer syntaxes that were supported up to Orthanc 0.7.1 - storageTransferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax); - storageTransferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax); - storageTransferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax); - - // New transfer syntaxes supported since Orthanc 0.7.2 - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Deflated)) - { - storageTransferSyntaxes.push_back(UID_DeflatedExplicitVRLittleEndianTransferSyntax); - } - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Jpeg)) - { - storageTransferSyntaxes.push_back(UID_JPEGProcess1TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess2_4TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess3_5TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess6_8TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess7_9TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess10_12TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess11_13TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess14TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess15TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess16_18TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess17_19TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess20_22TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess21_23TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess24_26TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess25_27TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess28TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess29TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGProcess14SV1TransferSyntax); - } - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Jpeg2000)) - { - storageTransferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEG2000TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEG2000TransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax); - } - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_JpegLossless)) - { - storageTransferSyntaxes.push_back(UID_JPEGLSLosslessTransferSyntax); - storageTransferSyntaxes.push_back(UID_JPEGLSLossyTransferSyntax); - } - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Jpip)) - { - storageTransferSyntaxes.push_back(UID_JPIPReferencedTransferSyntax); - storageTransferSyntaxes.push_back(UID_JPIPReferencedDeflateTransferSyntax); - } - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Mpeg2)) - { - storageTransferSyntaxes.push_back(UID_MPEG2MainProfileAtMainLevelTransferSyntax); - storageTransferSyntaxes.push_back(UID_MPEG2MainProfileAtHighLevelTransferSyntax); - } - -#if DCMTK_VERSION_NUMBER >= 361 - // New in Orthanc 1.6.0 - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Mpeg4)) - { - storageTransferSyntaxes.push_back(UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax); - storageTransferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_1TransferSyntax); - storageTransferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_2_For2DVideoTransferSyntax); - storageTransferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax); - storageTransferSyntaxes.push_back(UID_MPEG4StereoHighProfileLevel4_2TransferSyntax); - } -#endif - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Rle)) - { - storageTransferSyntaxes.push_back(UID_RLELosslessTransferSyntax); - } - - /* the array of Storage SOP Class UIDs that is defined within "dcmdata/libsrc/dcuid.cc" */ - size_t count = 0; - while (dcmAllStorageSOPClassUIDs[count] != NULL) - { - count++; - } - -#if DCMTK_VERSION_NUMBER >= 362 - // The global variable "numberOfDcmAllStorageSOPClassUIDs" is - // only published if DCMTK >= 3.6.2: - // https://bitbucket.org/sjodogne/orthanc/issues/137 - assert(static_cast(count) == numberOfDcmAllStorageSOPClassUIDs); -#endif - - if (!server.HasGetRequestHandlerFactory()) // dcmqrsrv.cc line 828 - { - // This branch exactly corresponds to Orthanc <= 1.6.1 (in - // which C-GET SCP was not supported) - cond = ASC_acceptContextsWithPreferredTransferSyntaxes( - assoc->params, dcmAllStorageSOPClassUIDs, count, - &storageTransferSyntaxes[0], storageTransferSyntaxes.size()); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - AssociationCleanup(assoc); - return NULL; - } - } - else // see dcmqrsrv.cc lines 839 - 876 - { - /* accept storage syntaxes with proposed role */ - int npc = ASC_countPresentationContexts(assoc->params); - for (int i = 0; i < npc; i++) - { - T_ASC_PresentationContext pc; - ASC_getPresentationContext(assoc->params, i, &pc); - if (dcmIsaStorageSOPClassUID(pc.abstractSyntax)) - { - /** - * We are prepared to accept whatever role the caller - * proposes. Normally we can be the SCP of the Storage - * Service Class. When processing the C-GET operation - * we can be the SCU of the Storage Service Class. - **/ - const T_ASC_SC_ROLE role = pc.proposedRole; - - /** - * Accept in the order "least wanted" to "most wanted" - * transfer syntax. Accepting a transfer syntax will - * override previously accepted transfer syntaxes. - **/ - for (int k = static_cast(storageTransferSyntaxes.size()) - 1; k >= 0; k--) - { - for (int j = 0; j < static_cast(pc.transferSyntaxCount); j++) - { - /** - * If the transfer syntax was proposed then we can accept it - * appears in our supported list of transfer syntaxes - **/ - if (strcmp(pc.proposedTransferSyntaxes[j], storageTransferSyntaxes[k]) == 0) - { - cond = ASC_acceptPresentationContext( - assoc->params, pc.presentationContextID, storageTransferSyntaxes[k], role); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - AssociationCleanup(assoc); - return NULL; - } - } - } - } - } - } /* for */ - } - - if (!server.HasApplicationEntityFilter() || - server.GetApplicationEntityFilter().IsUnknownSopClassAccepted(remoteIp, remoteAet, calledAet)) - { - /* - * Promiscous mode is enabled: Accept everything not known not - * to be a storage SOP class. - **/ - cond = acceptUnknownContextsWithPreferredTransferSyntaxes( - assoc->params, &storageTransferSyntaxes[0], storageTransferSyntaxes.size(), ASC_SC_ROLE_DEFAULT); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - AssociationCleanup(assoc); - return NULL; - } - } - } - - /* set our app title */ - ASC_setAPTitles(assoc->params, NULL, NULL, server.GetApplicationEntityTitle().c_str()); - - /* acknowledge or reject this association */ -#if DCMTK_VERSION_NUMBER >= 364 - cond = ASC_getApplicationContextName(assoc->params, buf, sizeof(buf)); -#else - cond = ASC_getApplicationContextName(assoc->params, buf); -#endif - - if ((cond.bad()) || strcmp(buf, UID_StandardApplicationContext) != 0) - { - /* reject: the application context name is not supported */ - T_ASC_RejectParameters rej = - { - ASC_RESULT_REJECTEDPERMANENT, - ASC_SOURCE_SERVICEUSER, - ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED - }; - - LOG(INFO) << "Association Rejected: Bad Application Context Name: " << buf; - cond = ASC_rejectAssociation(assoc, &rej); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - } - AssociationCleanup(assoc); - return NULL; - } - - /* check the AETs */ - if (!server.IsMyAETitle(calledAet)) - { - LOG(WARNING) << "Rejected association, because of a bad called AET in the request (" << calledAet << ")"; - T_ASC_RejectParameters rej = - { - ASC_RESULT_REJECTEDPERMANENT, - ASC_SOURCE_SERVICEUSER, - ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED - }; - ASC_rejectAssociation(assoc, &rej); - AssociationCleanup(assoc); - return NULL; - } - - if (server.HasApplicationEntityFilter() && - !server.GetApplicationEntityFilter().IsAllowedConnection(remoteIp, remoteAet, calledAet)) - { - LOG(WARNING) << "Rejected association for remote AET " << remoteAet << " on IP " << remoteIp; - T_ASC_RejectParameters rej = - { - ASC_RESULT_REJECTEDPERMANENT, - ASC_SOURCE_SERVICEUSER, - ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED - }; - ASC_rejectAssociation(assoc, &rej); - AssociationCleanup(assoc); - return NULL; - } - - if (opt_rejectWithoutImplementationUID && - strlen(assoc->params->theirImplementationClassUID) == 0) - { - /* reject: the no implementation Class UID provided */ - T_ASC_RejectParameters rej = - { - ASC_RESULT_REJECTEDPERMANENT, - ASC_SOURCE_SERVICEUSER, - ASC_REASON_SU_NOREASON - }; - - LOG(INFO) << "Association Rejected: No Implementation Class UID provided"; - cond = ASC_rejectAssociation(assoc, &rej); - if (cond.bad()) - { - LOG(INFO) << cond.text(); - } - AssociationCleanup(assoc); - return NULL; - } - - { - cond = ASC_acknowledgeAssociation(assoc); - if (cond.bad()) - { - LOG(ERROR) << cond.text(); - AssociationCleanup(assoc); - return NULL; - } - LOG(INFO) << "Association Acknowledged (Max Send PDV: " << assoc->sendPDVLength << ")"; - if (ASC_countAcceptedPresentationContexts(assoc->params) == 0) - LOG(INFO) << " (but no valid presentation contexts)"; - } - - IApplicationEntityFilter* filter = server.HasApplicationEntityFilter() ? &server.GetApplicationEntityFilter() : NULL; - return new CommandDispatcher(server, assoc, remoteIp, remoteAet, calledAet, filter); - } - - - CommandDispatcher::CommandDispatcher(const DicomServer& server, - T_ASC_Association* assoc, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - IApplicationEntityFilter* filter) : - server_(server), - assoc_(assoc), - remoteIp_(remoteIp), - remoteAet_(remoteAet), - calledAet_(calledAet), - filter_(filter) - { - associationTimeout_ = server.GetAssociationTimeout(); - elapsedTimeSinceLastCommand_ = 0; - } - - - CommandDispatcher::~CommandDispatcher() - { - try - { - AssociationCleanup(assoc_); - } - catch (...) - { - LOG(ERROR) << "Some association was not cleanly aborted"; - } - } - - - bool CommandDispatcher::Step() - /* - * This function receives DIMSE commmands over the network connection - * and handles these commands correspondingly. Note that in case of - * storscp only C-ECHO-RQ and C-STORE-RQ commands can be processed. - */ - { - bool finished = false; - - // receive a DIMSE command over the network, with a timeout of 1 second - DcmDataset *statusDetail = NULL; - T_ASC_PresentationContextID presID = 0; - T_DIMSE_Message msg; - - OFCondition cond = DIMSE_receiveCommand(assoc_, DIMSE_NONBLOCKING, 1, &presID, &msg, &statusDetail); - elapsedTimeSinceLastCommand_++; - - // if the command which was received has extra status - // detail information, dump this information - if (statusDetail != NULL) - { - //LOG4CPP_WARN(Internals::GetLogger(), "Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail)); - delete statusDetail; - } - - if (cond == DIMSE_OUTOFRESOURCES) - { - finished = true; - } - else if (cond == DIMSE_NODATAAVAILABLE) - { - // Timeout due to DIMSE_NONBLOCKING - if (associationTimeout_ != 0 && - elapsedTimeSinceLastCommand_ >= associationTimeout_) - { - // This timeout is actually a association timeout - finished = true; - } - } - else if (cond == EC_Normal) - { - // Reset the association timeout counter - elapsedTimeSinceLastCommand_ = 0; - - // Convert the type of request to Orthanc's internal type - bool supported = false; - DicomRequestType request; - switch (msg.CommandField) - { - case DIMSE_C_ECHO_RQ: - request = DicomRequestType_Echo; - supported = true; - break; - - case DIMSE_C_STORE_RQ: - request = DicomRequestType_Store; - supported = true; - break; - - case DIMSE_C_MOVE_RQ: - request = DicomRequestType_Move; - supported = true; - break; - - case DIMSE_C_GET_RQ: - request = DicomRequestType_Get; - supported = true; - break; - - case DIMSE_C_FIND_RQ: - request = DicomRequestType_Find; - supported = true; - break; - - case DIMSE_N_ACTION_RQ: - request = DicomRequestType_NAction; - supported = true; - break; - - case DIMSE_N_EVENT_REPORT_RQ: - request = DicomRequestType_NEventReport; - supported = true; - break; - - default: - // we cannot handle this kind of message - cond = DIMSE_BADCOMMANDTYPE; - LOG(ERROR) << "cannot handle command: 0x" << std::hex << msg.CommandField; - break; - } - - - // Check whether this request is allowed by the security filter - if (supported && - filter_ != NULL && - !filter_->IsAllowedRequest(remoteIp_, remoteAet_, calledAet_, request)) - { - LOG(WARNING) << "Rejected " << EnumerationToString(request) - << " request from remote DICOM modality with AET \"" - << remoteAet_ << "\" and hostname \"" << remoteIp_ << "\""; - cond = DIMSE_ILLEGALASSOCIATION; - supported = false; - finished = true; - } - - // in case we received a supported message, process this command - if (supported) - { - // If anything goes wrong, there will be a "BADCOMMANDTYPE" answer - cond = DIMSE_BADCOMMANDTYPE; - - switch (request) - { - case DicomRequestType_Echo: - cond = EchoScp(assoc_, &msg, presID); - break; - - case DicomRequestType_Store: - if (server_.HasStoreRequestHandlerFactory()) // Should always be true - { - std::unique_ptr handler - (server_.GetStoreRequestHandlerFactory().ConstructStoreRequestHandler()); - - if (handler.get() != NULL) - { - cond = Internals::storeScp(assoc_, &msg, presID, *handler, remoteIp_, associationTimeout_); - } - } - break; - - case DicomRequestType_Move: - if (server_.HasMoveRequestHandlerFactory()) // Should always be true - { - std::unique_ptr handler - (server_.GetMoveRequestHandlerFactory().ConstructMoveRequestHandler()); - - if (handler.get() != NULL) - { - cond = Internals::moveScp(assoc_, &msg, presID, *handler, remoteIp_, remoteAet_, calledAet_, associationTimeout_); - } - } - break; - - case DicomRequestType_Get: - if (server_.HasGetRequestHandlerFactory()) // Should always be true - { - std::unique_ptr handler - (server_.GetGetRequestHandlerFactory().ConstructGetRequestHandler()); - - if (handler.get() != NULL) - { - cond = Internals::getScp(assoc_, &msg, presID, *handler, remoteIp_, remoteAet_, calledAet_, associationTimeout_); - } - } - break; - - case DicomRequestType_Find: - if (server_.HasFindRequestHandlerFactory() || // Should always be true - server_.HasWorklistRequestHandlerFactory()) - { - std::unique_ptr findHandler; - if (server_.HasFindRequestHandlerFactory()) - { - findHandler.reset(server_.GetFindRequestHandlerFactory().ConstructFindRequestHandler()); - } - - std::unique_ptr worklistHandler; - if (server_.HasWorklistRequestHandlerFactory()) - { - worklistHandler.reset(server_.GetWorklistRequestHandlerFactory().ConstructWorklistRequestHandler()); - } - - cond = Internals::findScp(assoc_, &msg, presID, server_.GetRemoteModalities(), - findHandler.get(), worklistHandler.get(), - remoteIp_, remoteAet_, calledAet_, associationTimeout_); - } - break; - - case DicomRequestType_NAction: - cond = NActionScp(&msg, presID); - break; - - case DicomRequestType_NEventReport: - cond = NEventReportScp(&msg, presID); - break; - - default: - // Should never happen - break; - } - } - } - else - { - // Bad status, which indicates the closing of the connection by - // the peer or a network error - finished = true; - - LOG(INFO) << cond.text(); - } - - if (finished) - { - if (cond == DUL_PEERREQUESTEDRELEASE) - { - LOG(INFO) << "Association Release"; - ASC_acknowledgeRelease(assoc_); - } - else if (cond == DUL_PEERABORTEDASSOCIATION) - { - LOG(INFO) << "Association Aborted"; - } - else - { - OFString temp_str; - LOG(INFO) << "DIMSE failure (aborting association): " << cond.text(); - /* some kind of error so abort the association */ - ASC_abortAssociation(assoc_); - } - } - - return !finished; - } - - - OFCondition EchoScp(T_ASC_Association * assoc, T_DIMSE_Message * msg, T_ASC_PresentationContextID presID) - { - OFString temp_str; - LOG(INFO) << "Received Echo Request"; - //LOG(DEBUG) << DIMSE_dumpMessage(temp_str, msg->msg.CEchoRQ, DIMSE_INCOMING, NULL, presID)); - - /* the echo succeeded !! */ - OFCondition cond = DIMSE_sendEchoResponse(assoc, presID, &msg->msg.CEchoRQ, STATUS_Success, NULL); - if (cond.bad()) - { - LOG(ERROR) << "Echo SCP Failed: " << cond.text(); - } - return cond; - } - - - static DcmDataset* ReadDataset(T_ASC_Association* assoc, - const char* errorMessage, - int timeout) - { - DcmDataset *tmp = NULL; - T_ASC_PresentationContextID presIdData; - - OFCondition cond = DIMSE_receiveDataSetInMemory( - assoc, (timeout ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), timeout, - &presIdData, &tmp, NULL, NULL); - if (!cond.good() || - tmp == NULL) - { - throw OrthancException(ErrorCode_NetworkProtocol, errorMessage); - } - - return tmp; - } - - - static std::string ReadString(DcmDataset& dataset, - const DcmTagKey& tag) - { - const char* s = NULL; - if (!dataset.findAndGetString(tag, s).good() || - s == NULL) - { - char buf[64]; - sprintf(buf, "Missing mandatory tag in dataset: (%04X,%04X)", - tag.getGroup(), tag.getElement()); - throw OrthancException(ErrorCode_NetworkProtocol, buf); - } - - return std::string(s); - } - - - static void ReadSopSequence( - std::vector& sopClassUids, - std::vector& sopInstanceUids, - std::vector* failureReasons, // Can be NULL - DcmDataset& dataset, - const DcmTagKey& tag, - bool mandatory) - { - sopClassUids.clear(); - sopInstanceUids.clear(); - - if (failureReasons) - { - failureReasons->clear(); - } - - DcmSequenceOfItems* sequence = NULL; - if (!dataset.findAndGetSequence(tag, sequence).good() || - sequence == NULL) - { - if (mandatory) - { - char buf[64]; - sprintf(buf, "Missing mandatory sequence in dataset: (%04X,%04X)", - tag.getGroup(), tag.getElement()); - throw OrthancException(ErrorCode_NetworkProtocol, buf); - } - else - { - return; - } - } - - sopClassUids.reserve(sequence->card()); - sopInstanceUids.reserve(sequence->card()); - - if (failureReasons) - { - failureReasons->reserve(sequence->card()); - } - - for (unsigned long i = 0; i < sequence->card(); i++) - { - const char* a = NULL; - const char* b = NULL; - if (!sequence->getItem(i)->findAndGetString(DCM_ReferencedSOPClassUID, a).good() || - !sequence->getItem(i)->findAndGetString(DCM_ReferencedSOPInstanceUID, b).good() || - a == NULL || - b == NULL) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Missing Referenced SOP Class/Instance UID " - "in storage commitment dataset"); - } - - sopClassUids.push_back(a); - sopInstanceUids.push_back(b); - - if (failureReasons != NULL) - { - Uint16 reason; - if (!sequence->getItem(i)->findAndGetUint16(DCM_FailureReason, reason).good()) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Missing Failure Reason (0008,1197) " - "in storage commitment dataset"); - } - - failureReasons->push_back(static_cast(reason)); - } - } - } - - - OFCondition CommandDispatcher::NActionScp(T_DIMSE_Message* msg, - T_ASC_PresentationContextID presID) - { - /** - * Starting with Orthanc 1.6.0, only storage commitment is - * supported with DICOM N-ACTION. This corresponds to the case - * where "Action Type ID" equals "1". - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.2.html - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#table_10.1-4 - **/ - - if (msg->CommandField != DIMSE_N_ACTION_RQ /* value == 304 == 0x0130 */ || - !server_.HasStorageCommitmentRequestHandlerFactory()) - { - throw OrthancException(ErrorCode_InternalError); - } - - - /** - * Check that the storage commitment request is correctly formatted. - **/ - - const T_DIMSE_N_ActionRQ& request = msg->msg.NActionRQ; - - if (request.ActionTypeID != 1) - { - throw OrthancException(ErrorCode_NotImplemented, - "Only storage commitment is implemented for DICOM N-ACTION SCP"); - } - - if (std::string(request.RequestedSOPClassUID) != UID_StorageCommitmentPushModelSOPClass || - std::string(request.RequestedSOPInstanceUID) != UID_StorageCommitmentPushModelSOPInstance) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Unexpected incoming SOP class or instance UID for storage commitment"); - } - - if (request.DataSetType != DIMSE_DATASET_PRESENT) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Incoming storage commitment request without a dataset"); - } - - - /** - * Extract the DICOM dataset that is associated with the DIMSE - * message. The content of this dataset is documented in "Table - * J.3-1. Storage Commitment Request - Action Information": - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.2.html#table_J.3-1 - **/ - - std::unique_ptr dataset( - ReadDataset(assoc_, "Cannot read the dataset in N-ACTION SCP", associationTimeout_)); - - std::string transactionUid = ReadString(*dataset, DCM_TransactionUID); - - std::vector sopClassUid, sopInstanceUid; - ReadSopSequence(sopClassUid, sopInstanceUid, NULL, - *dataset, DCM_ReferencedSOPSequence, true /* mandatory */); - - LOG(INFO) << "Incoming storage commitment request, with transaction UID: " << transactionUid; - - for (size_t i = 0; i < sopClassUid.size(); i++) - { - LOG(INFO) << " (" << (i + 1) << "/" << sopClassUid.size() - << ") queried SOP Class/Instance UID: " - << sopClassUid[i] << " / " << sopInstanceUid[i]; - } - - - /** - * Call the Orthanc handler. The list of available DIMSE status - * codes can be found at: - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#sect_10.1.4.1.10 - **/ - - DIC_US dimseStatus; - - try - { - std::unique_ptr handler - (server_.GetStorageCommitmentRequestHandlerFactory(). - ConstructStorageCommitmentRequestHandler()); - - handler->HandleRequest(transactionUid, sopClassUid, sopInstanceUid, - remoteIp_, remoteAet_, calledAet_); - - dimseStatus = 0; // Success - } - catch (OrthancException& e) - { - LOG(ERROR) << "Error while processing an incoming storage commitment request: " << e.What(); - - // Code 0x0110 - "General failure in processing the operation was encountered" - dimseStatus = STATUS_N_ProcessingFailure; - } - - - /** - * Send the DIMSE status back to the SCU. - **/ - - { - T_DIMSE_Message response; - memset(&response, 0, sizeof(response)); - response.CommandField = DIMSE_N_ACTION_RSP; - - T_DIMSE_N_ActionRSP& content = response.msg.NActionRSP; - content.MessageIDBeingRespondedTo = request.MessageID; - strncpy(content.AffectedSOPClassUID, UID_StorageCommitmentPushModelSOPClass, DIC_UI_LEN); - content.DimseStatus = dimseStatus; - strncpy(content.AffectedSOPInstanceUID, UID_StorageCommitmentPushModelSOPInstance, DIC_UI_LEN); - content.ActionTypeID = 0; // Not present, as "O_NACTION_ACTIONTYPEID" not set in "opts" - content.DataSetType = DIMSE_DATASET_NULL; // Dataset is absent in storage commitment response - content.opts = O_NACTION_AFFECTEDSOPCLASSUID | O_NACTION_AFFECTEDSOPINSTANCEUID; - - return DIMSE_sendMessageUsingMemoryData( - assoc_, presID, &response, NULL /* no dataset */, NULL /* dataObject */, - NULL /* callback */, NULL /* callback context */, NULL /* commandSet */); - } - } - - - OFCondition CommandDispatcher::NEventReportScp(T_DIMSE_Message* msg, - T_ASC_PresentationContextID presID) - { - /** - * Starting with Orthanc 1.6.0, handling N-EVENT-REPORT for - * storage commitment. - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#table_10.1-1 - **/ - - if (msg->CommandField != DIMSE_N_EVENT_REPORT_RQ /* value == 256 == 0x0100 */ || - !server_.HasStorageCommitmentRequestHandlerFactory()) - { - throw OrthancException(ErrorCode_InternalError); - } - - - /** - * Check that the storage commitment report is correctly formatted. - **/ - - const T_DIMSE_N_EventReportRQ& report = msg->msg.NEventReportRQ; - - if (report.EventTypeID != 1 /* successful */ && - report.EventTypeID != 2 /* failures exist */) - { - throw OrthancException(ErrorCode_NotImplemented, - "Unknown event for DICOM N-EVENT-REPORT SCP"); - } - - if (std::string(report.AffectedSOPClassUID) != UID_StorageCommitmentPushModelSOPClass || - std::string(report.AffectedSOPInstanceUID) != UID_StorageCommitmentPushModelSOPInstance) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Unexpected incoming SOP class or instance UID for storage commitment"); - } - - if (report.DataSetType != DIMSE_DATASET_PRESENT) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Incoming storage commitment report without a dataset"); - } - - - /** - * Extract the DICOM dataset that is associated with the DIMSE - * message. The content of this dataset is documented in "Table - * J.3-2. Storage Commitment Result - Event Information": - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html#table_J.3-2 - **/ - - std::unique_ptr dataset( - ReadDataset(assoc_, "Cannot read the dataset in N-EVENT-REPORT SCP", associationTimeout_)); - - std::string transactionUid = ReadString(*dataset, DCM_TransactionUID); - - std::vector successSopClassUid, successSopInstanceUid; - ReadSopSequence(successSopClassUid, successSopInstanceUid, NULL, - *dataset, DCM_ReferencedSOPSequence, - (report.EventTypeID == 1) /* mandatory in the case of success */); - - std::vector failedSopClassUid, failedSopInstanceUid; - std::vector failureReasons; - - if (report.EventTypeID == 2 /* failures exist */) - { - ReadSopSequence(failedSopClassUid, failedSopInstanceUid, &failureReasons, - *dataset, DCM_FailedSOPSequence, true); - } - - LOG(INFO) << "Incoming storage commitment report, with transaction UID: " << transactionUid; - - for (size_t i = 0; i < successSopClassUid.size(); i++) - { - LOG(INFO) << " (success " << (i + 1) << "/" << successSopClassUid.size() - << ") SOP Class/Instance UID: " - << successSopClassUid[i] << " / " << successSopInstanceUid[i]; - } - - for (size_t i = 0; i < failedSopClassUid.size(); i++) - { - LOG(INFO) << " (failure " << (i + 1) << "/" << failedSopClassUid.size() - << ") SOP Class/Instance UID: " - << failedSopClassUid[i] << " / " << failedSopInstanceUid[i]; - } - - /** - * Call the Orthanc handler. The list of available DIMSE status - * codes can be found at: - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part07/chapter_10.html#sect_10.1.4.1.10 - **/ - - DIC_US dimseStatus; - - try - { - std::unique_ptr handler - (server_.GetStorageCommitmentRequestHandlerFactory(). - ConstructStorageCommitmentRequestHandler()); - - handler->HandleReport(transactionUid, successSopClassUid, successSopInstanceUid, - failedSopClassUid, failedSopInstanceUid, failureReasons, - remoteIp_, remoteAet_, calledAet_); - - dimseStatus = 0; // Success - } - catch (OrthancException& e) - { - LOG(ERROR) << "Error while processing an incoming storage commitment report: " << e.What(); - - // Code 0x0110 - "General failure in processing the operation was encountered" - dimseStatus = STATUS_N_ProcessingFailure; - } - - - /** - * Send the DIMSE status back to the SCU. - **/ - - { - T_DIMSE_Message response; - memset(&response, 0, sizeof(response)); - response.CommandField = DIMSE_N_EVENT_REPORT_RSP; - - T_DIMSE_N_EventReportRSP& content = response.msg.NEventReportRSP; - content.MessageIDBeingRespondedTo = report.MessageID; - strncpy(content.AffectedSOPClassUID, UID_StorageCommitmentPushModelSOPClass, DIC_UI_LEN); - content.DimseStatus = dimseStatus; - strncpy(content.AffectedSOPInstanceUID, UID_StorageCommitmentPushModelSOPInstance, DIC_UI_LEN); - content.EventTypeID = 0; // Not present, as "O_NEVENTREPORT_EVENTTYPEID" not set in "opts" - content.DataSetType = DIMSE_DATASET_NULL; // Dataset is absent in storage commitment response - content.opts = O_NEVENTREPORT_AFFECTEDSOPCLASSUID | O_NEVENTREPORT_AFFECTEDSOPINSTANCEUID; - - return DIMSE_sendMessageUsingMemoryData( - assoc_, presID, &response, NULL /* no dataset */, NULL /* dataObject */, - NULL /* callback */, NULL /* callback context */, NULL /* commandSet */); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/CommandDispatcher.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../DicomServer.h" -#include "../../MultiThreading/IRunnableBySteps.h" - -#include - -namespace Orthanc -{ - namespace Internals - { - OFCondition AssociationCleanup(T_ASC_Association *assoc); - - class CommandDispatcher : public IRunnableBySteps - { - private: - uint32_t associationTimeout_; - uint32_t elapsedTimeSinceLastCommand_; - const DicomServer& server_; - T_ASC_Association* assoc_; - std::string remoteIp_; - std::string remoteAet_; - std::string calledAet_; - IApplicationEntityFilter* filter_; - - OFCondition NActionScp(T_DIMSE_Message* msg, - T_ASC_PresentationContextID presID); - - OFCondition NEventReportScp(T_DIMSE_Message* msg, - T_ASC_PresentationContextID presID); - - public: - CommandDispatcher(const DicomServer& server, - T_ASC_Association* assoc, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - IApplicationEntityFilter* filter); - - virtual ~CommandDispatcher(); - - virtual bool Step(); - }; - - CommandDispatcher* AcceptAssociation(const DicomServer& server, - T_ASC_Network *net); - - OFCondition EchoScp(T_ASC_Association* assoc, - T_DIMSE_Message* msg, - T_ASC_PresentationContextID presID); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,375 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: DCMTK 3.6.0 - Module: http://dicom.offis.de/dcmtk.php.en - -Copyright (C) 1994-2011, OFFIS e.V. -All rights reserved. - -This software and supporting documentation were developed by - - OFFIS e.V. - R&D Division Health - Escherweg 2 - 26121 Oldenburg, Germany - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -- Neither the name of OFFIS nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 COPYRIGHT -HOLDER OR CONTRIBUTORS 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. - -=========================================================================*/ - - - -#include "../../PrecompiledHeaders.h" -#include "FindScp.h" - -#include "../../DicomFormat/DicomArray.h" -#include "../../DicomParsing/FromDcmtkBridge.h" -#include "../../DicomParsing/ToDcmtkBridge.h" -#include "../../Logging.h" -#include "../../OrthancException.h" - -#include -#include - - - -/** - * The function below is extracted from DCMTK 3.6.0, cf. file - * "dcmtk-3.6.0/dcmwlm/libsrc/wldsfs.cc". - **/ - -static void HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(DcmDataset *dataset, - const DcmTagKey &sequenceTagKey) -// Date : May 3, 2005 -// Author : Thomas Wilkens -// Task : This function performs a check on a sequence attribute in the given dataset. At two different places -// in the definition of the DICOM worklist management service, a sequence attribute with a return type -// of 2 is mentioned containing two 1C attributes in its item; the condition of the two 1C attributes -// specifies that in case a sequence item is present, then these two attributes must be existent and -// must contain a value. (I am talking about ReferencedStudySequence and ReferencedPatientSequence.) -// In cases where the sequence attribute contains exactly one item with an empty ReferencedSOPClass -// and an empty ReferencedSOPInstance, we want to remove the item from the sequence. This is what -// this function does. -// Parameters : dataset - [in] Dataset in which the consistency of the sequence attribute shall be checked. -// sequenceTagKey - [in] DcmTagKey of the sequence attribute which shall be checked. -// Return Value : none. -{ - DcmElement *sequenceAttribute = NULL, *referencedSOPClassUIDAttribute = NULL, *referencedSOPInstanceUIDAttribute = NULL; - - // in case the sequence attribute contains exactly one item with an empty - // ReferencedSOPClassUID and an empty ReferencedSOPInstanceUID, remove the item - if( dataset->findAndGetElement( sequenceTagKey, sequenceAttribute ).good() && - ( (DcmSequenceOfItems*)sequenceAttribute )->card() == 1 && - ( (DcmSequenceOfItems*)sequenceAttribute )->getItem(0)->findAndGetElement( DCM_ReferencedSOPClassUID, referencedSOPClassUIDAttribute ).good() && - referencedSOPClassUIDAttribute->getLength() == 0 && - ( (DcmSequenceOfItems*)sequenceAttribute )->getItem(0)->findAndGetElement( DCM_ReferencedSOPInstanceUID, referencedSOPInstanceUIDAttribute, OFFalse ).good() && - referencedSOPInstanceUIDAttribute->getLength() == 0 ) - { - DcmItem *item = ((DcmSequenceOfItems*)sequenceAttribute)->remove( ((DcmSequenceOfItems*)sequenceAttribute)->getItem(0) ); - delete item; - } -} - - - -namespace Orthanc -{ - namespace - { - struct FindScpData - { - DicomServer::IRemoteModalities* modalities_; - IFindRequestHandler* findHandler_; - IWorklistRequestHandler* worklistHandler_; - DicomFindAnswers answers_; - DcmDataset* lastRequest_; - const std::string* remoteIp_; - const std::string* remoteAet_; - const std::string* calledAet_; - - FindScpData() : answers_(false) - { - } - }; - - - - static void FixWorklistQuery(ParsedDicomFile& query) - { - // TODO: Check out - // WlmDataSourceFileSystem::HandleExistentButEmptyDescriptionAndCodeSequenceAttributes()" - // in DCMTK 3.6.0 - - DcmDataset* dataset = query.GetDcmtkObject().getDataset(); - HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(dataset, DCM_ReferencedStudySequence); - HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(dataset, DCM_ReferencedPatientSequence); - } - - - static void FixFindQuery(DicomMap& target, - const DicomMap& source) - { - // "The definition of a Data Set in PS3.5 specifically excludes - // the range of groups below group 0008, and this includes in - // particular Meta Information Header elements such as Transfer - // Syntax UID (0002,0010)." - // http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.html#sect_C.4.1.1.3 - // https://groups.google.com/d/msg/orthanc-users/D3kpPuX8yV0/_zgHOzkMEQAJ - - DicomArray a(source); - - for (size_t i = 0; i < a.GetSize(); i++) - { - if (a.GetElement(i).GetTag().GetGroup() >= 0x0008) - { - target.SetValue(a.GetElement(i).GetTag(), a.GetElement(i).GetValue()); - } - } - } - - - - void FindScpCallback( - /* in */ - void *callbackData, - OFBool cancelled, - T_DIMSE_C_FindRQ *request, - DcmDataset *requestIdentifiers, - int responseCount, - /* out */ - T_DIMSE_C_FindRSP *response, - DcmDataset **responseIdentifiers, - DcmDataset **statusDetail) - { - bzero(response, sizeof(T_DIMSE_C_FindRSP)); - *statusDetail = NULL; - - std::string sopClassUid(request->AffectedSOPClassUID); - - FindScpData& data = *reinterpret_cast(callbackData); - if (data.lastRequest_ == NULL) - { - bool ok = false; - - try - { - RemoteModalityParameters modality; - - /** - * Ensure that the remote modality is known to Orthanc for C-FIND requests. - **/ - - assert(data.modalities_ != NULL); - if (!data.modalities_->LookupAETitle(modality, *data.remoteAet_)) - { - throw OrthancException(ErrorCode_UnknownModality, - "Modality with AET \"" + (*data.remoteAet_) + - "\" is not defined in the \"DicomModalities\" configuration option"); - } - - - if (sopClassUid == UID_FINDModalityWorklistInformationModel) - { - data.answers_.SetWorklist(true); - - if (data.worklistHandler_ != NULL) - { - ParsedDicomFile query(*requestIdentifiers); - FixWorklistQuery(query); - - data.worklistHandler_->Handle(data.answers_, query, - *data.remoteIp_, *data.remoteAet_, - *data.calledAet_, modality.GetManufacturer()); - ok = true; - } - else - { - LOG(ERROR) << "No worklist handler is installed, cannot handle this C-FIND request"; - } - } - else - { - data.answers_.SetWorklist(false); - - if (data.findHandler_ != NULL) - { - std::list sequencesToReturn; - - for (unsigned long i = 0; i < requestIdentifiers->card(); i++) - { - DcmElement* element = requestIdentifiers->getElement(i); - if (element && !element->isLeaf()) - { - const DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); - - DcmSequenceOfItems& sequence = dynamic_cast(*element); - if (sequence.card() != 0) - { - LOG(WARNING) << "Orthanc only supports sequence matching on worklists, " - << "ignoring C-FIND SCU constraint on tag (" << tag.Format() - << ") " << FromDcmtkBridge::GetTagName(*element); - } - - sequencesToReturn.push_back(tag); - } - } - - DicomMap input; - FromDcmtkBridge::ExtractDicomSummary(input, *requestIdentifiers); - - DicomMap filtered; - FixFindQuery(filtered, input); - - data.findHandler_->Handle(data.answers_, filtered, sequencesToReturn, - *data.remoteIp_, *data.remoteAet_, - *data.calledAet_, modality.GetManufacturer()); - ok = true; - } - else - { - LOG(ERROR) << "No C-Find handler is installed, cannot handle this request"; - } - } - } - catch (OrthancException& e) - { - // Internal error! - LOG(ERROR) << "C-FIND request handler has failed: " << e.What(); - } - - if (!ok) - { - response->DimseStatus = STATUS_FIND_Failed_UnableToProcess; - *responseIdentifiers = NULL; - return; - } - - data.lastRequest_ = requestIdentifiers; - } - else if (data.lastRequest_ != requestIdentifiers) - { - // Internal error! - response->DimseStatus = STATUS_FIND_Failed_UnableToProcess; - *responseIdentifiers = NULL; - return; - } - - if (responseCount <= static_cast(data.answers_.GetSize())) - { - // There are pending results that are still to be sent - response->DimseStatus = STATUS_Pending; - *responseIdentifiers = data.answers_.ExtractDcmDataset(responseCount - 1); - } - else if (data.answers_.IsComplete()) - { - // Success: All the results have been sent - response->DimseStatus = STATUS_Success; - *responseIdentifiers = NULL; - } - else - { - // Success, but the results were too numerous and had to be cropped - LOG(WARNING) << "Too many results for an incoming C-FIND query"; - response->DimseStatus = STATUS_FIND_Cancel_MatchingTerminatedDueToCancelRequest; - *responseIdentifiers = NULL; - } - } - } - - - OFCondition Internals::findScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - DicomServer::IRemoteModalities& modalities, - IFindRequestHandler* findHandler, - IWorklistRequestHandler* worklistHandler, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - int timeout) - { - FindScpData data; - data.modalities_ = &modalities; - data.findHandler_ = findHandler; - data.worklistHandler_ = worklistHandler; - data.lastRequest_ = NULL; - data.remoteIp_ = &remoteIp; - data.remoteAet_ = &remoteAet; - data.calledAet_ = &calledAet; - - OFCondition cond = DIMSE_findProvider(assoc, presID, &msg->msg.CFindRQ, - FindScpCallback, &data, - /*opt_blockMode*/ (timeout ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ timeout); - - // if some error occured, dump corresponding information and remove the outfile if necessary - if (cond.bad()) - { - OFString temp_str; - LOG(ERROR) << "Find SCP Failed: " << cond.text(); - } - - return cond; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/FindScp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../DicomServer.h" - -#include - -namespace Orthanc -{ - namespace Internals - { - OFCondition findScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - DicomServer::IRemoteModalities& modalities, - IFindRequestHandler* findHandler, // can be NULL - IWorklistRequestHandler* worklistHandler, // can be NULL - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - int timeout); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,289 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: DCMTK 3.6.0 - Module: http://dicom.offis.de/dcmtk.php.en - - Copyright (C) 1994-2011, OFFIS e.V. - All rights reserved. - - This software and supporting documentation were developed by - - OFFIS e.V. - R&D Division Health - Escherweg 2 - 26121 Oldenburg, Germany - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - - Neither the name of OFFIS nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "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 COPYRIGHT - HOLDER OR CONTRIBUTORS 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. - - =========================================================================*/ - - -#include "../../PrecompiledHeaders.h" -#include -#include -#include "GetScp.h" - -#include - -#include "../../DicomParsing/FromDcmtkBridge.h" -#include "../../DicomParsing/ToDcmtkBridge.h" -#include "../../Logging.h" -#include "../../OrthancException.h" - -#include - - -namespace Orthanc -{ - namespace - { - struct GetScpData - { - // Handle returns void. - IGetRequestHandler* handler_; - DcmDataset* lastRequest_; - T_ASC_Association * assoc_; - - std::string remoteIp_; - std::string remoteAet_; - std::string calledAet_; - int timeout_; - - GetScpData() - { - handler_ = NULL; - lastRequest_ = NULL; - assoc_ = NULL; - }; - }; - - static DcmDataset *BuildFailedInstanceList(const std::string& failedUIDs) - { - if (failedUIDs.empty()) - { - return NULL; - } - else - { - std::unique_ptr rspIds(new DcmDataset()); - - if (!DU_putStringDOElement(rspIds.get(), DCM_FailedSOPInstanceUIDList, failedUIDs.c_str())) - { - throw OrthancException(ErrorCode_InternalError, - "getSCP: failed to build DCM_FailedSOPInstanceUIDList"); - } - - return rspIds.release(); - } - } - - static void GetScpCallback( - /* in */ - void *callbackData, - OFBool cancelled, - T_DIMSE_C_GetRQ *request, - DcmDataset *requestIdentifiers, - int responseCount, - /* out */ - T_DIMSE_C_GetRSP *response, - DcmDataset **responseIdentifiers, - DcmDataset **statusDetail) - { - bzero(response, sizeof(T_DIMSE_C_GetRSP)); - *statusDetail = NULL; - *responseIdentifiers = NULL; - - GetScpData& data = *reinterpret_cast(callbackData); - if (data.lastRequest_ == NULL) - { - DicomMap input; - FromDcmtkBridge::ExtractDicomSummary(input, *requestIdentifiers); - - try - { - if (!data.handler_->Handle( - input, data.remoteIp_, data.remoteAet_, data.calledAet_, - data.timeout_ < 0 ? 0 : static_cast(data.timeout_))) - { - response->DimseStatus = STATUS_GET_Failed_UnableToProcess; - return; - } - } - catch (OrthancException& e) - { - // Internal error! - LOG(ERROR) << "IGetRequestHandler Failed: " << e.What(); - response->DimseStatus = STATUS_GET_Failed_UnableToProcess; - return; - } - - data.lastRequest_ = requestIdentifiers; - } - else if (data.lastRequest_ != requestIdentifiers) - { - // Internal error! - LOG(ERROR) << "IGetRequestHandler Failed: Internal error lastRequestIdentifier"; - response->DimseStatus = STATUS_GET_Failed_UnableToProcess; - return; - } - - if (data.handler_->GetRemainingCount() == 0) - { - response->DimseStatus = STATUS_Success; - } - else - { - IGetRequestHandler::Status status; - - try - { - status = data.handler_->DoNext(data.assoc_); - } - catch (OrthancException& e) - { - // Internal error! - LOG(ERROR) << "IGetRequestHandler Failed: " << e.What(); - response->DimseStatus = STATUS_GET_Failed_UnableToProcess; - return; - } - - if (status == STATUS_Success) - { - if (responseCount < static_cast(data.handler_->GetRemainingCount())) - { - response->DimseStatus = STATUS_Pending; - } - else - { - response->DimseStatus = STATUS_Success; - } - } - else - { - response->DimseStatus = STATUS_GET_Failed_UnableToProcess; - - if (data.handler_->GetFailedCount() > 0 || - data.handler_->GetWarningCount() > 0) - { - response->DimseStatus = STATUS_GET_Warning_SubOperationsCompleteOneOrMoreFailures; - } - - /* - * if all the sub-operations failed then we need to generate - * a failed or refused status. cf. DICOM part 4, C.4.3.3.1 - * we choose to generate a "Refused - Out of Resources - - * Unable to perform suboperations" status. - */ - if ((data.handler_->GetFailedCount() > 0) && - ((data.handler_->GetCompletedCount() + - data.handler_->GetWarningCount()) == 0)) - { - response->DimseStatus = STATUS_GET_Refused_OutOfResourcesSubOperations; - } - - *responseIdentifiers = BuildFailedInstanceList(data.handler_->GetFailedUids()); - } - } - - response->NumberOfRemainingSubOperations = data.handler_->GetRemainingCount(); - response->NumberOfCompletedSubOperations = data.handler_->GetCompletedCount(); - response->NumberOfFailedSubOperations = data.handler_->GetFailedCount(); - response->NumberOfWarningSubOperations = data.handler_->GetWarningCount(); - } - } - - OFCondition Internals::getScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - IGetRequestHandler& handler, - std::string remoteIp, - std::string remoteAet, - std::string calledAet, - int timeout) - { - GetScpData data; - data.lastRequest_ = NULL; - data.handler_ = &handler; - data.assoc_ = assoc; - data.remoteIp_ = remoteIp; - data.remoteAet_ = remoteAet; - data.calledAet_ = calledAet; - data.timeout_ = timeout; - - OFCondition cond = DIMSE_getProvider(assoc, presID, &msg->msg.CGetRQ, - GetScpCallback, &data, - /*opt_blockMode*/ (timeout ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ timeout); - - // if some error occured, dump corresponding information and remove the outfile if necessary - if (cond.bad()) - { - OFString temp_str; - LOG(ERROR) << "Get SCP Failed: " << cond.text(); - } - - return cond; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/GetScp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IGetRequestHandler.h" - -namespace Orthanc -{ - namespace Internals - { - OFCondition getScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - IGetRequestHandler& handler, - std::string remoteIp, - std::string remoteAet, - std::string calledAet, - int timeout); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,300 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: DCMTK 3.6.0 - Module: http://dicom.offis.de/dcmtk.php.en - -Copyright (C) 1994-2011, OFFIS e.V. -All rights reserved. - -This software and supporting documentation were developed by - - OFFIS e.V. - R&D Division Health - Escherweg 2 - 26121 Oldenburg, Germany - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -- Neither the name of OFFIS nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 COPYRIGHT -HOLDER OR CONTRIBUTORS 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. - -=========================================================================*/ - - -#include "../../PrecompiledHeaders.h" -#include "MoveScp.h" - -#include - -#include "../../DicomParsing/FromDcmtkBridge.h" -#include "../../DicomParsing/ToDcmtkBridge.h" -#include "../../Logging.h" -#include "../../OrthancException.h" - -#include - - -/** - * Macro specifying whether to apply the patch suggested in issue 66: - * "Orthanc responses C-MOVE with zero Move Originator Message ID" - * https://bitbucket.org/sjodogne/orthanc/issues/66/ - **/ - -#define APPLY_FIX_ISSUE_66 1 - - -namespace Orthanc -{ - namespace - { - struct MoveScpData - { - std::string target_; - IMoveRequestHandler* handler_; - DcmDataset* lastRequest_; - unsigned int subOperationCount_; - unsigned int failureCount_; - unsigned int warningCount_; - std::unique_ptr iterator_; - const std::string* remoteIp_; - const std::string* remoteAet_; - const std::string* calledAet_; - }; - - -#if APPLY_FIX_ISSUE_66 != 1 - static uint16_t GetMessageId(const DicomMap& message) - { - /** - * Retrieve the Message ID (0000,0110) for this C-MOVE request, if - * any. If present, this Message ID will be stored in the Move - * Originator Message ID (0000,1031) field of the C-MOVE response. - * http://dicom.nema.org/dicom/2013/output/chtml/part07/chapter_E.html - **/ - - const DicomValue* value = message.TestAndGetValue(DICOM_TAG_MESSAGE_ID); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - try - { - int tmp = boost::lexical_cast(value->GetContent()); - if (tmp >= 0 && tmp <= 0xffff) - { - return static_cast(tmp); - } - } - catch (boost::bad_lexical_cast&) - { - LOG(WARNING) << "Cannot convert the Message ID (\"" << value->GetContent() - << "\") of an incoming C-MOVE request to an integer, assuming zero"; - } - } - - return 0; - } -#endif - - - void MoveScpCallback( - /* in */ - void *callbackData, - OFBool cancelled, - T_DIMSE_C_MoveRQ *request, - DcmDataset *requestIdentifiers, - int responseCount, - /* out */ - T_DIMSE_C_MoveRSP *response, - DcmDataset **responseIdentifiers, - DcmDataset **statusDetail) - { - bzero(response, sizeof(T_DIMSE_C_MoveRSP)); - *statusDetail = NULL; - *responseIdentifiers = NULL; - - MoveScpData& data = *reinterpret_cast(callbackData); - if (data.lastRequest_ == NULL) - { - DicomMap input; - FromDcmtkBridge::ExtractDicomSummary(input, *requestIdentifiers); - - try - { -#if APPLY_FIX_ISSUE_66 == 1 - uint16_t messageId = request->MessageID; -#else - // The line below was the implementation for Orthanc <= 1.3.2 - uint16_t messageId = GetMessageId(input); -#endif - - data.iterator_.reset(data.handler_->Handle(data.target_, input, *data.remoteIp_, *data.remoteAet_, - *data.calledAet_, messageId)); - - if (data.iterator_.get() == NULL) - { - // Internal error! - response->DimseStatus = STATUS_MOVE_Failed_UnableToProcess; - return; - } - - data.subOperationCount_ = data.iterator_->GetSubOperationCount(); - data.failureCount_ = 0; - data.warningCount_ = 0; - } - catch (OrthancException& e) - { - // Internal error! - LOG(ERROR) << "IMoveRequestHandler Failed: " << e.What(); - response->DimseStatus = STATUS_MOVE_Failed_UnableToProcess; - return; - } - - data.lastRequest_ = requestIdentifiers; - } - else if (data.lastRequest_ != requestIdentifiers) - { - // Internal error! - response->DimseStatus = STATUS_MOVE_Failed_UnableToProcess; - return; - } - - if (data.subOperationCount_ == 0) - { - response->DimseStatus = STATUS_Success; - } - else - { - IMoveRequestIterator::Status status; - - try - { - status = data.iterator_->DoNext(); - } - catch (OrthancException& e) - { - // Internal error! - LOG(ERROR) << "IMoveRequestHandler Failed: " << e.What(); - response->DimseStatus = STATUS_MOVE_Failed_UnableToProcess; - return; - } - - if (status == IMoveRequestIterator::Status_Failure) - { - data.failureCount_++; - } - else if (status == IMoveRequestIterator::Status_Warning) - { - data.warningCount_++; - } - - if (responseCount < static_cast(data.subOperationCount_)) - { - response->DimseStatus = STATUS_Pending; - } - else - { - response->DimseStatus = STATUS_Success; - } - } - - response->NumberOfRemainingSubOperations = data.subOperationCount_ - responseCount; - response->NumberOfCompletedSubOperations = responseCount; - response->NumberOfFailedSubOperations = data.failureCount_; - response->NumberOfWarningSubOperations = data.warningCount_; - } - } - - - OFCondition Internals::moveScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - IMoveRequestHandler& handler, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - int timeout) - { - MoveScpData data; - data.target_ = std::string(msg->msg.CMoveRQ.MoveDestination); - data.lastRequest_ = NULL; - data.handler_ = &handler; - data.remoteIp_ = &remoteIp; - data.remoteAet_ = &remoteAet; - data.calledAet_ = &calledAet; - - OFCondition cond = DIMSE_moveProvider(assoc, presID, &msg->msg.CMoveRQ, - MoveScpCallback, &data, - /*opt_blockMode*/ (timeout ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ timeout); - - // if some error occured, dump corresponding information and remove the outfile if necessary - if (cond.bad()) - { - OFString temp_str; - LOG(ERROR) << "Move SCP Failed: " << cond.text(); - } - - return cond; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/MoveScp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IMoveRequestHandler.h" - -#include - -namespace Orthanc -{ - namespace Internals - { - OFCondition moveScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - IMoveRequestHandler& handler, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - int timeout); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,311 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: DCMTK 3.6.0 - Module: http://dicom.offis.de/dcmtk.php.en - -Copyright (C) 1994-2011, OFFIS e.V. -All rights reserved. - -This software and supporting documentation were developed by - - OFFIS e.V. - R&D Division Health - Escherweg 2 - 26121 Oldenburg, Germany - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -- Neither the name of OFFIS nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 COPYRIGHT -HOLDER OR CONTRIBUTORS 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. - -=========================================================================*/ - - -#include "../../PrecompiledHeaders.h" -#include "StoreScp.h" - -#if !defined(DCMTK_VERSION_NUMBER) -# error The macro DCMTK_VERSION_NUMBER must be defined -#endif - -#include "../../DicomParsing/FromDcmtkBridge.h" -#include "../../DicomParsing/ToDcmtkBridge.h" -#include "../../OrthancException.h" -#include "../../Logging.h" - -#include -#include -#include -#include -#include - - -namespace Orthanc -{ - namespace - { - struct StoreCallbackData - { - IStoreRequestHandler* handler; - const std::string* remoteIp; - const char* remoteAET; - const char* calledAET; - const char* modality; - const char* affectedSOPInstanceUID; - uint32_t messageID; - }; - - - static void - storeScpCallback( - void *callbackData, - T_DIMSE_StoreProgress *progress, - T_DIMSE_C_StoreRQ *req, - char * /*imageFileName*/, DcmDataset **imageDataSet, - T_DIMSE_C_StoreRSP *rsp, - DcmDataset **statusDetail) - /* - * This function.is used to indicate progress when storescp receives instance data over the - * network. On the final call to this function (identified by progress->state == DIMSE_StoreEnd) - * this function will store the data set which was received over the network to a file. - * Earlier calls to this function will simply cause some information to be dumped to stdout. - * - * Parameters: - * callbackData - [in] data for this callback function - * progress - [in] The state of progress. (identifies if this is the initial or final call - * to this function, or a call in between these two calls. - * req - [in] The original store request message. - * imageFileName - [in] The path to and name of the file the information shall be written to. - * imageDataSet - [in] The data set which shall be stored in the image file - * rsp - [inout] the C-STORE-RSP message (will be sent after the call to this function) - * statusDetail - [inout] This variable can be used to capture detailed information with regard to - * the status information which is captured in the status element (0000,0900). Note - * that this function does specify any such information, the pointer will be set to NULL. - */ - { - StoreCallbackData *cbdata = OFstatic_cast(StoreCallbackData *, callbackData); - - DIC_UI sopClass; - DIC_UI sopInstance; - - // if this is the final call of this function, save the data which was received to a file - // (note that we could also save the image somewhere else, put it in database, etc.) - if (progress->state == DIMSE_StoreEnd) - { - OFString tmpStr; - - // do not send status detail information - *statusDetail = NULL; - - // Concerning the following line: an appropriate status code is already set in the resp structure, - // it need not be success. For example, if the caller has already detected an out of resources problem - // then the status will reflect this. The callback function is still called to allow cleanup. - //rsp->DimseStatus = STATUS_Success; - - // we want to write the received information to a file only if this information - // is present and the options opt_bitPreserving and opt_ignore are not set. - if ((imageDataSet != NULL) && (*imageDataSet != NULL)) - { - DicomMap summary; - Json::Value dicomJson; - std::string buffer; - - try - { - std::set ignoreTagLength; - - FromDcmtkBridge::ExtractDicomSummary(summary, **imageDataSet); - FromDcmtkBridge::ExtractDicomAsJson(dicomJson, **imageDataSet, ignoreTagLength); - - if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, **imageDataSet)) - { - LOG(ERROR) << "cannot write DICOM file to memory"; - rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources; - } - } - catch (...) - { - rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources; - } - - // check the image to make sure it is consistent, i.e. that its sopClass and sopInstance correspond - // to those mentioned in the request. If not, set the status in the response message variable. - if (rsp->DimseStatus == STATUS_Success) - { - // which SOP class and SOP instance ? - -#if DCMTK_VERSION_NUMBER >= 364 - if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sizeof(sopClass), - sopInstance, sizeof(sopInstance), /*opt_correctUIDPadding*/ OFFalse)) -#else - if (!DU_findSOPClassAndInstanceInDataSet(*imageDataSet, sopClass, sopInstance, /*opt_correctUIDPadding*/ OFFalse)) -#endif - { - //LOG4CPP_ERROR(Internals::GetLogger(), "bad DICOM file: " << fileName); - rsp->DimseStatus = STATUS_STORE_Error_CannotUnderstand; - } - else if (strcmp(sopClass, req->AffectedSOPClassUID) != 0) - { - rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass; - } - else if (strcmp(sopInstance, req->AffectedSOPInstanceUID) != 0) - { - rsp->DimseStatus = STATUS_STORE_Error_DataSetDoesNotMatchSOPClass; - } - else - { - try - { - cbdata->handler->Handle(buffer, summary, dicomJson, *cbdata->remoteIp, cbdata->remoteAET, cbdata->calledAET); - } - catch (OrthancException& e) - { - rsp->DimseStatus = STATUS_STORE_Refused_OutOfResources; - - if (e.GetErrorCode() == ErrorCode_InexistentTag) - { - summary.LogMissingTagsForStore(); - } - else - { - LOG(ERROR) << "Exception while storing DICOM: " << e.What(); - } - } - } - } - } - } - } - } - -/* - * This function processes a DIMSE C-STORE-RQ commmand that was - * received over the network connection. - * - * Parameters: - * assoc - [in] The association (network connection to another DICOM application). - * msg - [in] The DIMSE C-STORE-RQ message that was received. - * presID - [in] The ID of the presentation context which was specified in the PDV which contained - * the DIMSE command. - */ - OFCondition Internals::storeScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - IStoreRequestHandler& handler, - const std::string& remoteIp, - int timeout) - { - OFCondition cond = EC_Normal; - T_DIMSE_C_StoreRQ *req; - - // assign the actual information of the C-STORE-RQ command to a local variable - req = &msg->msg.CStoreRQ; - - // intialize some variables - StoreCallbackData data; - data.handler = &handler; - data.remoteIp = &remoteIp; - data.modality = dcmSOPClassUIDToModality(req->AffectedSOPClassUID/*, "UNKNOWN"*/); - if (data.modality == NULL) - data.modality = "UNKNOWN"; - - data.affectedSOPInstanceUID = req->AffectedSOPInstanceUID; - data.messageID = req->MessageID; - if (assoc && assoc->params) - { - data.remoteAET = assoc->params->DULparams.callingAPTitle; - data.calledAET = assoc->params->DULparams.calledAPTitle; - } - else - { - data.remoteAET = ""; - data.calledAET = ""; - } - - DcmFileFormat dcmff; - - // store SourceApplicationEntityTitle in metaheader - if (assoc && assoc->params) - { - const char *aet = assoc->params->DULparams.callingAPTitle; - if (aet) dcmff.getMetaInfo()->putAndInsertString(DCM_SourceApplicationEntityTitle, aet); - } - - // define an address where the information which will be received over the network will be stored - DcmDataset *dset = dcmff.getDataset(); - - cond = DIMSE_storeProvider(assoc, presID, req, NULL, /*opt_useMetaheader*/OFFalse, &dset, - storeScpCallback, &data, - /*opt_blockMode*/ (timeout ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), - /*opt_dimse_timeout*/ timeout); - - // if some error occured, dump corresponding information and remove the outfile if necessary - if (cond.bad()) - { - OFString temp_str; - LOG(ERROR) << "Store SCP Failed: " << cond.text(); - } - - // return return value - return cond; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/Internals/StoreScp.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IStoreRequestHandler.h" - -#include - -namespace Orthanc -{ - namespace Internals - { - OFCondition storeScp(T_ASC_Association * assoc, - T_DIMSE_Message * msg, - T_ASC_PresentationContextID presID, - IStoreRequestHandler& handler, - const std::string& remoteIp, - int timeout); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandlerFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IStorageCommitmentRequestHandler.h" - -namespace Orthanc -{ - class IStorageCommitmentRequestHandlerFactory : public boost::noncopyable - { - public: - virtual ~IStorageCommitmentRequestHandlerFactory() - { - } - - virtual IStorageCommitmentRequestHandler* ConstructStorageCommitmentRequestHandler() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStorageCommitmentRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include -#include - -namespace Orthanc -{ - class IStorageCommitmentRequestHandler : public boost::noncopyable - { - public: - virtual ~IStorageCommitmentRequestHandler() - { - } - - virtual void HandleRequest(const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) = 0; - - virtual void HandleReport(const std::string& transactionUid, - const std::vector& successSopClassUids, - const std::vector& successSopInstanceUids, - const std::vector& failedSopClassUids, - const std::vector& failedSopInstanceUids, - const std::vector& failureReasons, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandlerFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandlerFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandlerFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandlerFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IStoreRequestHandler.h" - -namespace Orthanc -{ - class IStoreRequestHandlerFactory : public boost::noncopyable - { - public: - virtual ~IStoreRequestHandlerFactory() - { - } - - virtual IStoreRequestHandler* ConstructStoreRequestHandler() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IStoreRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../DicomFormat/DicomMap.h" - -#include -#include -#include - -namespace Orthanc -{ - class IStoreRequestHandler : public boost::noncopyable - { - public: - virtual ~IStoreRequestHandler() - { - } - - virtual void Handle(const std::string& dicomFile, - const DicomMap& dicomSummary, - const Json::Value& dicomJson, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandlerFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandlerFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandlerFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandlerFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IWorklistRequestHandler.h" - -namespace Orthanc -{ - class IWorklistRequestHandlerFactory : public boost::noncopyable - { - public: - virtual ~IWorklistRequestHandlerFactory() - { - } - - virtual IWorklistRequestHandler* ConstructWorklistRequestHandler() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/IWorklistRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomFindAnswers.h" - -namespace Orthanc -{ - class IWorklistRequestHandler : public boost::noncopyable - { - public: - virtual ~IWorklistRequestHandler() - { - } - - virtual void Handle(DicomFindAnswers& answers, - ParsedDicomFile& query, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/NetworkingCompatibility.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/NetworkingCompatibility.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/NetworkingCompatibility.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/NetworkingCompatibility.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - - -#ifdef _WIN32 -/** - * "The maximum length, in bytes, of the string returned in the buffer - * pointed to by the name parameter is dependent on the namespace provider, - * but this string must be 256 bytes or less. - * http://msdn.microsoft.com/en-us/library/windows/desktop/ms738527(v=vs.85).aspx - **/ -# define HOST_NAME_MAX 256 -# include -#endif - - -#if !defined(HOST_NAME_MAX) && defined(_POSIX_HOST_NAME_MAX) -/** - * TO IMPROVE: "_POSIX_HOST_NAME_MAX is only the minimum value that - * HOST_NAME_MAX can ever have [...] Therefore you cannot allocate an - * array of size _POSIX_HOST_NAME_MAX, invoke gethostname() and expect - * that the result will fit." - * http://lists.gnu.org/archive/html/bug-gnulib/2009-08/msg00128.html - **/ -# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,378 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RemoteModalityParameters.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../SerializationToolbox.h" - -#include -#include - - -static const char* KEY_AET = "AET"; -static const char* KEY_ALLOW_ECHO = "AllowEcho"; -static const char* KEY_ALLOW_FIND = "AllowFind"; -static const char* KEY_ALLOW_GET = "AllowGet"; -static const char* KEY_ALLOW_MOVE = "AllowMove"; -static const char* KEY_ALLOW_STORE = "AllowStore"; -static const char* KEY_ALLOW_N_ACTION = "AllowNAction"; -static const char* KEY_ALLOW_N_EVENT_REPORT = "AllowEventReport"; -static const char* KEY_ALLOW_STORAGE_COMMITMENT = "AllowStorageCommitment"; -static const char* KEY_ALLOW_TRANSCODING = "AllowTranscoding"; -static const char* KEY_HOST = "Host"; -static const char* KEY_MANUFACTURER = "Manufacturer"; -static const char* KEY_PORT = "Port"; - - -namespace Orthanc -{ - void RemoteModalityParameters::Clear() - { - aet_ = "ORTHANC"; - host_ = "127.0.0.1"; - port_ = 104; - manufacturer_ = ModalityManufacturer_Generic; - allowEcho_ = true; - allowStore_ = true; - allowFind_ = true; - allowMove_ = true; - allowGet_ = true; - allowNAction_ = true; // For storage commitment - allowNEventReport_ = true; // For storage commitment - allowTranscoding_ = true; - } - - - RemoteModalityParameters::RemoteModalityParameters(const std::string& aet, - const std::string& host, - uint16_t port, - ModalityManufacturer manufacturer) - { - Clear(); - SetApplicationEntityTitle(aet); - SetHost(host); - SetPortNumber(port); - SetManufacturer(manufacturer); - } - - - static void CheckPortNumber(int value) - { - if (value <= 0 || - value >= 65535) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "A TCP port number must be in range [1..65534], but found: " + - boost::lexical_cast(value)); - } - } - - - static uint16_t ReadPortNumber(const Json::Value& value) - { - int tmp; - - switch (value.type()) - { - case Json::intValue: - case Json::uintValue: - tmp = value.asInt(); - break; - - case Json::stringValue: - try - { - tmp = boost::lexical_cast(value.asString()); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - break; - - default: - throw OrthancException(ErrorCode_BadFileFormat); - } - - CheckPortNumber(tmp); - return static_cast(tmp); - } - - - void RemoteModalityParameters::SetPortNumber(uint16_t port) - { - CheckPortNumber(port); - port_ = port; - } - - - void RemoteModalityParameters::UnserializeArray(const Json::Value& serialized) - { - assert(serialized.type() == Json::arrayValue); - - if ((serialized.size() != 3 && - serialized.size() != 4) || - serialized[0].type() != Json::stringValue || - serialized[1].type() != Json::stringValue || - (serialized.size() == 4 && - serialized[3].type() != Json::stringValue)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - aet_ = serialized[0].asString(); - host_ = serialized[1].asString(); - port_ = ReadPortNumber(serialized[2]); - - if (serialized.size() == 4) - { - manufacturer_ = StringToModalityManufacturer(serialized[3].asString()); - } - else - { - manufacturer_ = ModalityManufacturer_Generic; - } - } - - - void RemoteModalityParameters::UnserializeObject(const Json::Value& serialized) - { - assert(serialized.type() == Json::objectValue); - - aet_ = SerializationToolbox::ReadString(serialized, KEY_AET); - host_ = SerializationToolbox::ReadString(serialized, KEY_HOST); - - if (serialized.isMember(KEY_PORT)) - { - port_ = ReadPortNumber(serialized[KEY_PORT]); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - if (serialized.isMember(KEY_MANUFACTURER)) - { - manufacturer_ = StringToModalityManufacturer - (SerializationToolbox::ReadString(serialized, KEY_MANUFACTURER)); - } - else - { - manufacturer_ = ModalityManufacturer_Generic; - } - - if (serialized.isMember(KEY_ALLOW_ECHO)) - { - allowEcho_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_ECHO); - } - - if (serialized.isMember(KEY_ALLOW_FIND)) - { - allowFind_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_FIND); - } - - if (serialized.isMember(KEY_ALLOW_STORE)) - { - allowStore_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_STORE); - } - - if (serialized.isMember(KEY_ALLOW_GET)) - { - allowGet_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_GET); - } - - if (serialized.isMember(KEY_ALLOW_MOVE)) - { - allowMove_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_MOVE); - } - - if (serialized.isMember(KEY_ALLOW_N_ACTION)) - { - allowNAction_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_N_ACTION); - } - - if (serialized.isMember(KEY_ALLOW_N_EVENT_REPORT)) - { - allowNEventReport_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_N_EVENT_REPORT); - } - - if (serialized.isMember(KEY_ALLOW_STORAGE_COMMITMENT)) - { - bool allow = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_STORAGE_COMMITMENT); - allowNAction_ = allow; - allowNEventReport_ = allow; - } - - if (serialized.isMember(KEY_ALLOW_TRANSCODING)) - { - allowTranscoding_ = SerializationToolbox::ReadBoolean(serialized, KEY_ALLOW_TRANSCODING); - } - } - - - bool RemoteModalityParameters::IsRequestAllowed(DicomRequestType type) const - { - switch (type) - { - case DicomRequestType_Echo: - return allowEcho_; - - case DicomRequestType_Find: - return allowFind_; - - case DicomRequestType_Get: - return allowGet_; - - case DicomRequestType_Move: - return allowMove_; - - case DicomRequestType_Store: - return allowStore_; - - case DicomRequestType_NAction: - return allowNAction_; - - case DicomRequestType_NEventReport: - return allowNEventReport_; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - void RemoteModalityParameters::SetRequestAllowed(DicomRequestType type, - bool allowed) - { - switch (type) - { - case DicomRequestType_Echo: - allowEcho_ = allowed; - break; - - case DicomRequestType_Find: - allowFind_ = allowed; - break; - - case DicomRequestType_Get: - allowGet_ = allowed; - break; - - case DicomRequestType_Move: - allowMove_ = allowed; - break; - - case DicomRequestType_Store: - allowStore_ = allowed; - break; - - case DicomRequestType_NAction: - allowNAction_ = allowed; - break; - - case DicomRequestType_NEventReport: - allowNEventReport_ = allowed; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool RemoteModalityParameters::IsAdvancedFormatNeeded() const - { - return (!allowEcho_ || - !allowStore_ || - !allowFind_ || - !allowGet_ || - !allowMove_ || - !allowNAction_ || - !allowNEventReport_ || - !allowTranscoding_); - } - - - void RemoteModalityParameters::Serialize(Json::Value& target, - bool forceAdvancedFormat) const - { - if (forceAdvancedFormat || - IsAdvancedFormatNeeded()) - { - target = Json::objectValue; - target[KEY_AET] = aet_; - target[KEY_HOST] = host_; - target[KEY_PORT] = port_; - target[KEY_MANUFACTURER] = EnumerationToString(manufacturer_); - target[KEY_ALLOW_ECHO] = allowEcho_; - target[KEY_ALLOW_STORE] = allowStore_; - target[KEY_ALLOW_FIND] = allowFind_; - target[KEY_ALLOW_GET] = allowGet_; - target[KEY_ALLOW_MOVE] = allowMove_; - target[KEY_ALLOW_N_ACTION] = allowNAction_; - target[KEY_ALLOW_N_EVENT_REPORT] = allowNEventReport_; - target[KEY_ALLOW_TRANSCODING] = allowTranscoding_; - } - else - { - target = Json::arrayValue; - target.append(GetApplicationEntityTitle()); - target.append(GetHost()); - target.append(GetPortNumber()); - target.append(EnumerationToString(GetManufacturer())); - } - } - - - void RemoteModalityParameters::Unserialize(const Json::Value& serialized) - { - Clear(); - - switch (serialized.type()) - { - case Json::objectValue: - UnserializeObject(serialized); - break; - - case Json::arrayValue: - UnserializeArray(serialized); - break; - - default: - throw OrthancException(ErrorCode_BadFileFormat); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/RemoteModalityParameters.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include -#include -#include - -namespace Orthanc -{ - class RemoteModalityParameters - { - private: - std::string aet_; - std::string host_; - uint16_t port_; - ModalityManufacturer manufacturer_; - bool allowEcho_; - bool allowStore_; - bool allowFind_; - bool allowMove_; - bool allowGet_; - bool allowNAction_; - bool allowNEventReport_; - bool allowTranscoding_; - - void Clear(); - - void UnserializeArray(const Json::Value& serialized); - - void UnserializeObject(const Json::Value& serialized); - - public: - RemoteModalityParameters() - { - Clear(); - } - - RemoteModalityParameters(const Json::Value& serialized) - { - Unserialize(serialized); - } - - RemoteModalityParameters(const std::string& aet, - const std::string& host, - uint16_t port, - ModalityManufacturer manufacturer); - - const std::string& GetApplicationEntityTitle() const - { - return aet_; - } - - void SetApplicationEntityTitle(const std::string& aet) - { - aet_ = aet; - } - - const std::string& GetHost() const - { - return host_; - } - - void SetHost(const std::string& host) - { - host_ = host; - } - - uint16_t GetPortNumber() const - { - return port_; - } - - void SetPortNumber(uint16_t port); - - ModalityManufacturer GetManufacturer() const - { - return manufacturer_; - } - - void SetManufacturer(ModalityManufacturer manufacturer) - { - manufacturer_ = manufacturer; - } - - void SetManufacturer(const std::string& manufacturer) - { - manufacturer_ = StringToModalityManufacturer(manufacturer); - } - - bool IsRequestAllowed(DicomRequestType type) const; - - void SetRequestAllowed(DicomRequestType type, - bool allowed); - - void Unserialize(const Json::Value& modality); - - bool IsAdvancedFormatNeeded() const; - - void Serialize(Json::Value& target, - bool forceAdvancedFormat) const; - - bool IsTranscodingAllowed() const - { - return allowTranscoding_; - } - - void SetTranscodingAllowed(bool allowed) - { - allowTranscoding_ = allowed; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "TimeoutDicomConnectionManager.h" - -#include "../Logging.h" -#include "../OrthancException.h" - -namespace Orthanc -{ - static boost::posix_time::ptime GetNow() - { - return boost::posix_time::microsec_clock::universal_time(); - } - - - TimeoutDicomConnectionManager::Lock::Lock(TimeoutDicomConnectionManager& that, - const std::string& localAet, - const RemoteModalityParameters& remote) : - that_(that), - lock_(that_.mutex_) - { - // Calling "Touch()" will be done by the "~Lock()" destructor - that_.OpenInternal(localAet, remote); - } - - - TimeoutDicomConnectionManager::Lock::~Lock() - { - that_.TouchInternal(); - } - - - DicomStoreUserConnection& TimeoutDicomConnectionManager::Lock::GetConnection() - { - if (that_.connection_.get() == NULL) - { - // The allocation should have been done by "that_.Open()" in the constructor - throw OrthancException(ErrorCode_InternalError); - } - else - { - return *that_.connection_; - } - } - - - // Mutex must be locked - void TimeoutDicomConnectionManager::TouchInternal() - { - lastUse_ = GetNow(); - } - - - // Mutex must be locked - void TimeoutDicomConnectionManager::OpenInternal(const std::string& localAet, - const RemoteModalityParameters& remote) - { - DicomAssociationParameters other(localAet, remote); - - if (connection_.get() == NULL || - !connection_->GetParameters().IsEqual(other)) - { - connection_.reset(new DicomStoreUserConnection(other)); - } - } - - - // Mutex must be locked - void TimeoutDicomConnectionManager::CloseInternal() - { - if (connection_.get() != NULL) - { - LOG(INFO) << "Closing inactive DICOM association with modality: " - << connection_->GetParameters().GetRemoteModality().GetApplicationEntityTitle(); - - connection_.reset(NULL); - } - } - - - void TimeoutDicomConnectionManager::SetInactivityTimeout(unsigned int milliseconds) - { - boost::mutex::scoped_lock lock(mutex_); - timeout_ = boost::posix_time::milliseconds(milliseconds); - CloseInternal(); - } - - - unsigned int TimeoutDicomConnectionManager::GetInactivityTimeout() - { - boost::mutex::scoped_lock lock(mutex_); - return static_cast(timeout_.total_milliseconds()); - } - - - void TimeoutDicomConnectionManager::CloseIfInactive() - { - boost::mutex::scoped_lock lock(mutex_); - - if (connection_.get() != NULL && - (GetNow() - lastUse_) >= timeout_) - { - CloseInternal(); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomNetworking/TimeoutDicomConnectionManager.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_DCMTK_NETWORKING) -# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be defined -#endif - -#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1 -# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be 1 to use this file -#endif - - -#include "../Compatibility.h" -#include "DicomStoreUserConnection.h" - -#include -#include - -namespace Orthanc -{ - /** - * This class corresponds to a singleton to a DICOM SCU connection. - **/ - class TimeoutDicomConnectionManager : public boost::noncopyable - { - private: - boost::mutex mutex_; - std::unique_ptr connection_; - boost::posix_time::ptime lastUse_; - boost::posix_time::time_duration timeout_; - - // Mutex must be locked - void TouchInternal(); - - // Mutex must be locked - void OpenInternal(const std::string& localAet, - const RemoteModalityParameters& remote); - - // Mutex must be locked - void CloseInternal(); - - public: - class Lock : public boost::noncopyable - { - private: - TimeoutDicomConnectionManager& that_; - boost::mutex::scoped_lock lock_; - - public: - Lock(TimeoutDicomConnectionManager& that, - const std::string& localAet, - const RemoteModalityParameters& remote); - - ~Lock(); - - DicomStoreUserConnection& GetConnection(); - }; - - TimeoutDicomConnectionManager() : - timeout_(boost::posix_time::milliseconds(1000)) - { - } - - void SetInactivityTimeout(unsigned int milliseconds); - - unsigned int GetInactivityTimeout(); // In milliseconds - - void Close(); - - void CloseIfInactive(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,330 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DcmtkTranscoder.h" - - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG) -# error Macro ORTHANC_ENABLE_DCMTK_JPEG must be defined -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) -# error Macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined -#endif - - -#include "FromDcmtkBridge.h" -#include "../OrthancException.h" - -#include -#include // for DJ_RPLossy -#include // for DJ_RPLossless -#include // for DJLSRepresentationParameter - - -namespace Orthanc -{ - static bool GetBitsStored(uint16_t& bitsStored, - DcmDataset& dataset) - { - return dataset.findAndGetUint16(DCM_BitsStored, bitsStored).good(); - } - - - void DcmtkTranscoder::SetLossyQuality(unsigned int quality) - { - if (quality <= 0 || - quality > 100) - { - throw OrthancException( - ErrorCode_ParameterOutOfRange, - "The quality for lossy transcoding must be an integer between 1 and 100, received: " + - boost::lexical_cast(quality)); - } - else - { - LOG(INFO) << "Quality for lossy transcoding using DCMTK is set to: " << quality; - lossyQuality_ = quality; - } - } - - - bool DcmtkTranscoder::InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, - DcmFileFormat& dicom, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomTransferSyntax syntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(syntax, dicom)) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax"); - } - - uint16_t bitsStored; - bool hasBitsStored = GetBitsStored(bitsStored, *dicom.getDataset()); - - std::string sourceSopInstanceUid = IDicomTranscoder::GetSopInstanceUid(dicom); - - if (allowedSyntaxes.find(syntax) != allowedSyntaxes.end()) - { - // No transcoding is needed - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianImplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianImplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_LittleEndianImplicit; - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_LittleEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_LittleEndianExplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_LittleEndianExplicit; - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_BigEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_BigEndianExplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_BigEndianExplicit; - return true; - } - - if (allowedSyntaxes.find(DicomTransferSyntax_DeflatedLittleEndianExplicit) != allowedSyntaxes.end() && - FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_DeflatedLittleEndianExplicit, NULL)) - { - selectedSyntax = DicomTransferSyntax_DeflatedLittleEndianExplicit; - return true; - } - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess1) != allowedSyntaxes.end() && - allowNewSopInstanceUid && - (!hasBitsStored || bitsStored == 8)) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossy parameters(lossyQuality_); - - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess1, ¶meters)) - { - selectedSyntax = DicomTransferSyntax_JPEGProcess1; - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess2_4) != allowedSyntaxes.end() && - allowNewSopInstanceUid && - (!hasBitsStored || bitsStored <= 12)) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossy parameters(lossyQuality_); - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess2_4, ¶meters)) - { - selectedSyntax = DicomTransferSyntax_JPEGProcess2_4; - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess14) != allowedSyntaxes.end()) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossless parameters(6 /* opt_selection_value */, - 0 /* opt_point_transform */); - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14, ¶meters)) - { - selectedSyntax = DicomTransferSyntax_JPEGProcess14; - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGProcess14SV1) != allowedSyntaxes.end()) - { - // Check out "dcmjpeg/apps/dcmcjpeg.cc" - DJ_RPLossless parameters(6 /* opt_selection_value */, - 0 /* opt_point_transform */); - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGProcess14SV1, ¶meters)) - { - selectedSyntax = DicomTransferSyntax_JPEGProcess14SV1; - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - if (allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossless) != allowedSyntaxes.end()) - { - // Check out "dcmjpls/apps/dcmcjpls.cc" - DJLSRepresentationParameter parameters(2 /* opt_nearlossless_deviation */, - OFTrue /* opt_useLosslessProcess */); - - /** - * WARNING: This call results in a segmentation fault if using - * the DCMTK package 3.6.2 from Ubuntu 18.04. - **/ - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossless, ¶meters)) - { - selectedSyntax = DicomTransferSyntax_JPEGLSLossless; - return true; - } - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - if (allowNewSopInstanceUid && - allowedSyntaxes.find(DicomTransferSyntax_JPEGLSLossy) != allowedSyntaxes.end()) - { - // Check out "dcmjpls/apps/dcmcjpls.cc" - DJLSRepresentationParameter parameters(2 /* opt_nearlossless_deviation */, - OFFalse /* opt_useLosslessProcess */); - - /** - * WARNING: This call results in a segmentation fault if using - * the DCMTK package 3.6.2 from Ubuntu 18.04. - **/ - if (FromDcmtkBridge::Transcode(dicom, DicomTransferSyntax_JPEGLSLossy, ¶meters)) - { - selectedSyntax = DicomTransferSyntax_JPEGLSLossy; - return true; - } - } -#endif - - return false; - } - - - bool DcmtkTranscoder::IsSupported(DicomTransferSyntax syntax) - { - if (syntax == DicomTransferSyntax_LittleEndianImplicit || - syntax == DicomTransferSyntax_LittleEndianExplicit || - syntax == DicomTransferSyntax_BigEndianExplicit || - syntax == DicomTransferSyntax_DeflatedLittleEndianExplicit) - { - return true; - } - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - if (syntax == DicomTransferSyntax_JPEGProcess1 || - syntax == DicomTransferSyntax_JPEGProcess2_4 || - syntax == DicomTransferSyntax_JPEGProcess14 || - syntax == DicomTransferSyntax_JPEGProcess14SV1) - { - return true; - } -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - if (syntax == DicomTransferSyntax_JPEGLSLossless || - syntax == DicomTransferSyntax_JPEGLSLossy) - { - return true; - } -#endif - - return false; - } - - - bool DcmtkTranscoder::Transcode(DicomImage& target, - DicomImage& source /* in, "GetParsed()" possibly modified */, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - target.Clear(); - - DicomTransferSyntax sourceSyntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(sourceSyntax, source.GetParsed())) - { - LOG(ERROR) << "Unsupport transfer syntax for transcoding"; - return false; - } - -#if !defined(NDEBUG) - const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed()); -#endif - - DicomTransferSyntax targetSyntax; - if (allowedSyntaxes.find(sourceSyntax) != allowedSyntaxes.end()) - { - // No transcoding is needed - target.AcquireParsed(source); - target.AcquireBuffer(source); - return true; - } - else if (InplaceTranscode(targetSyntax, source.GetParsed(), - allowedSyntaxes, allowNewSopInstanceUid)) - { - // Sanity check - DicomTransferSyntax targetSyntax2; - if (FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax2, source.GetParsed()) && - targetSyntax == targetSyntax2 && - allowedSyntaxes.find(targetSyntax2) != allowedSyntaxes.end()) - { - target.AcquireParsed(source); - source.Clear(); - -#if !defined(NDEBUG) - // Only run the sanity check in debug mode - CheckTranscoding(target, sourceSyntax, sourceSopInstanceUid, - allowedSyntaxes, allowNewSopInstanceUid); -#endif - - return true; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - // Cannot transcode - return false; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DcmtkTranscoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_DCMTK_TRANSCODING) -# error Macro ORTHANC_ENABLE_DCMTK_TRANSCODING must be defined to use this file -#endif - -#if ORTHANC_ENABLE_DCMTK_TRANSCODING != 1 -# error Transcoding is disabled, cannot compile this file -#endif - -#include "IDicomTranscoder.h" - -namespace Orthanc -{ - class DcmtkTranscoder : public IDicomTranscoder - { - private: - unsigned int lossyQuality_; - - bool InplaceTranscode(DicomTransferSyntax& selectedSyntax /* out */, - DcmFileFormat& dicom, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid); - - public: - DcmtkTranscoder() : - lossyQuality_(90) - { - } - - void SetLossyQuality(unsigned int quality); - - unsigned int GetLossyQuality() const - { - return lossyQuality_; - } - - static bool IsSupported(DicomTransferSyntax syntax); - - virtual bool Transcode(DicomImage& target, - DicomImage& source /* in, "GetParsed()" possibly modified */, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,602 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: DCMTK 3.6.0 - Module: http://dicom.offis.de/dcmtk.php.en - -Copyright (C) 1994-2011, OFFIS e.V. -All rights reserved. - -This software and supporting documentation were developed by - - OFFIS e.V. - R&D Division Health - Escherweg 2 - 26121 Oldenburg, Germany - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -- Neither the name of OFFIS nor the names of its contributors may be - used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 COPYRIGHT -HOLDER OR CONTRIBUTORS 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. - -=========================================================================*/ - - - -/*** - - Validation: - - # sudo apt-get install dicom3tools - # dciodvfy DICOMDIR 2>&1 | less - # dcentvfy DICOMDIR 2>&1 | less - - http://www.dclunie.com/dicom3tools/dciodvfy.html - - DICOMDIR viewer working with Wine under Linux: - http://www.microdicom.com/ - - ***/ - - -#include "../PrecompiledHeaders.h" -#include "DicomDirWriter.h" - -#include "FromDcmtkBridge.h" -#include "ToDcmtkBridge.h" - -#include "../Compatibility.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../TemporaryFile.h" -#include "../Toolbox.h" -#include "../SystemToolbox.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include "dcmtk/dcmdata/dcvrda.h" /* for class DcmDate */ -#include "dcmtk/dcmdata/dcvrtm.h" /* for class DcmTime */ - -#include - -namespace Orthanc -{ - class DicomDirWriter::PImpl - { - private: - bool utc_; - std::string fileSetId_; - bool extendedSopClass_; - TemporaryFile file_; - std::unique_ptr dir_; - - typedef std::pair IndexKey; - typedef std::map Index; - Index index_; - - - DcmDicomDir& GetDicomDir() - { - if (dir_.get() == NULL) - { - dir_.reset(new DcmDicomDir(file_.GetPath().c_str(), - fileSetId_.c_str())); - //SetTagValue(dir_->getRootRecord(), DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(Encoding_Utf8)); - } - - return *dir_; - } - - - DcmDirectoryRecord& GetRoot() - { - return GetDicomDir().getRootRecord(); - } - - - static bool GetUtf8TagValue(std::string& result, - DcmItem& source, - Encoding encoding, - bool hasCodeExtensions, - const DcmTagKey& key) - { - DcmElement* element = NULL; - result.clear(); - - if (source.findAndGetElement(key, element).good()) - { - char* s = NULL; - if (element->isLeaf() && - element->getString(s).good()) - { - if (s != NULL) - { - result = Toolbox::ConvertToUtf8(s, encoding, hasCodeExtensions); - } - - return true; - } - } - - return false; - } - - - static void SetTagValue(DcmDirectoryRecord& target, - const DcmTagKey& key, - const std::string& valueUtf8) - { - std::string s = Toolbox::ConvertFromUtf8(valueUtf8, Encoding_Ascii); - - if (!target.putAndInsertString(key, s.c_str()).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - - static bool CopyString(DcmDirectoryRecord& target, - DcmDataset& source, - Encoding encoding, - bool hasCodeExtensions, - const DcmTagKey& key, - bool optional, - bool copyEmpty) - { - if (optional && - !source.tagExistsWithValue(key) && - !(copyEmpty && source.tagExists(key))) - { - return false; - } - - std::string value; - bool found = GetUtf8TagValue(value, source, encoding, hasCodeExtensions, key); - - if (!found) - { - // We don't raise an exception if "!optional", even if this - // results in an invalid DICOM file - value.clear(); - } - - SetTagValue(target, key, value); - return found; - } - - - static void CopyStringType1(DcmDirectoryRecord& target, - DcmDataset& source, - Encoding encoding, - bool hasCodeExtensions, - const DcmTagKey& key) - { - CopyString(target, source, encoding, hasCodeExtensions, key, false, false); - } - - static void CopyStringType1C(DcmDirectoryRecord& target, - DcmDataset& source, - Encoding encoding, - bool hasCodeExtensions, - const DcmTagKey& key) - { - CopyString(target, source, encoding, hasCodeExtensions, key, true, false); - } - - static void CopyStringType2(DcmDirectoryRecord& target, - DcmDataset& source, - Encoding encoding, - bool hasCodeExtensions, - const DcmTagKey& key) - { - CopyString(target, source, encoding, hasCodeExtensions, key, false, true); - } - - static void CopyStringType3(DcmDirectoryRecord& target, - DcmDataset& source, - Encoding encoding, - bool hasCodeExtensions, - const DcmTagKey& key) - { - CopyString(target, source, encoding, hasCodeExtensions, key, true, true); - } - - - public: - PImpl() : - utc_(true), // By default, use UTC (universal time, not local time) - fileSetId_("ORTHANC_MEDIA"), - extendedSopClass_(false) - { - } - - bool IsUtcUsed() const - { - return utc_; - } - - - void SetUtcUsed(bool utc) - { - utc_ = utc; - } - - void EnableExtendedSopClass(bool enable) - { - if (enable) - { - LOG(WARNING) << "Generating a DICOMDIR with type 3 attributes, " - << "which leads to an Extended SOP Class"; - } - - extendedSopClass_ = enable; - } - - bool IsExtendedSopClass() const - { - return extendedSopClass_; - } - - void FillPatient(DcmDirectoryRecord& record, - DcmDataset& dicom, - Encoding encoding, - bool hasCodeExtensions) - { - // cf. "DicomDirInterface::buildPatientRecord()" - - CopyStringType1C(record, dicom, encoding, hasCodeExtensions, DCM_PatientID); - CopyStringType2(record, dicom, encoding, hasCodeExtensions, DCM_PatientName); - } - - void FillStudy(DcmDirectoryRecord& record, - DcmDataset& dicom, - Encoding encoding, - bool hasCodeExtensions) - { - // cf. "DicomDirInterface::buildStudyRecord()" - - std::string nowDate, nowTime; - SystemToolbox::GetNowDicom(nowDate, nowTime, utc_); - - std::string studyDate; - if (!GetUtf8TagValue(studyDate, dicom, encoding, hasCodeExtensions, DCM_StudyDate) && - !GetUtf8TagValue(studyDate, dicom, encoding, hasCodeExtensions, DCM_SeriesDate) && - !GetUtf8TagValue(studyDate, dicom, encoding, hasCodeExtensions, DCM_AcquisitionDate) && - !GetUtf8TagValue(studyDate, dicom, encoding, hasCodeExtensions, DCM_ContentDate)) - { - studyDate = nowDate; - } - - std::string studyTime; - if (!GetUtf8TagValue(studyTime, dicom, encoding, hasCodeExtensions, DCM_StudyTime) && - !GetUtf8TagValue(studyTime, dicom, encoding, hasCodeExtensions, DCM_SeriesTime) && - !GetUtf8TagValue(studyTime, dicom, encoding, hasCodeExtensions, DCM_AcquisitionTime) && - !GetUtf8TagValue(studyTime, dicom, encoding, hasCodeExtensions, DCM_ContentTime)) - { - studyTime = nowTime; - } - - /* copy attribute values from dataset to study record */ - SetTagValue(record, DCM_StudyDate, studyDate); - SetTagValue(record, DCM_StudyTime, studyTime); - CopyStringType2(record, dicom, encoding, hasCodeExtensions, DCM_StudyDescription); - CopyStringType1(record, dicom, encoding, hasCodeExtensions, DCM_StudyInstanceUID); - /* use type 1C instead of 1 in order to avoid unwanted overwriting */ - CopyStringType1C(record, dicom, encoding, hasCodeExtensions, DCM_StudyID); - CopyStringType2(record, dicom, encoding, hasCodeExtensions, DCM_AccessionNumber); - } - - void FillSeries(DcmDirectoryRecord& record, - DcmDataset& dicom, - Encoding encoding, - bool hasCodeExtensions) - { - // cf. "DicomDirInterface::buildSeriesRecord()" - - /* copy attribute values from dataset to series record */ - CopyStringType1(record, dicom, encoding, hasCodeExtensions, DCM_Modality); - CopyStringType1(record, dicom, encoding, hasCodeExtensions, DCM_SeriesInstanceUID); - /* use type 1C instead of 1 in order to avoid unwanted overwriting */ - CopyStringType1C(record, dicom, encoding, hasCodeExtensions, DCM_SeriesNumber); - - // Add extended (non-standard) type 3 tags, those are not generated by DCMTK - // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part02/sect_7.3.html - // https://groups.google.com/d/msg/orthanc-users/Y7LOvZMDeoc/9cp3kDgxAwAJ - if (extendedSopClass_) - { - CopyStringType3(record, dicom, encoding, hasCodeExtensions, DCM_SeriesDescription); - } - } - - void FillInstance(DcmDirectoryRecord& record, - DcmDataset& dicom, - Encoding encoding, - bool hasCodeExtensions, - DcmMetaInfo& metaInfo, - const char* path) - { - // cf. "DicomDirInterface::buildImageRecord()" - - /* copy attribute values from dataset to image record */ - CopyStringType1(record, dicom, encoding, hasCodeExtensions, DCM_InstanceNumber); - //CopyElementType1C(record, dicom, encoding, hasCodeExtensions, DCM_ImageType); - - // REMOVED since 0.9.7: copyElementType1C(dicom, DCM_ReferencedImageSequence, record); - - std::string sopClassUid, sopInstanceUid, transferSyntaxUid; - if (!GetUtf8TagValue(sopClassUid, dicom, encoding, hasCodeExtensions, DCM_SOPClassUID) || - !GetUtf8TagValue(sopInstanceUid, dicom, encoding, hasCodeExtensions, DCM_SOPInstanceUID) || - !GetUtf8TagValue(transferSyntaxUid, metaInfo, encoding, hasCodeExtensions, DCM_TransferSyntaxUID)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - SetTagValue(record, DCM_ReferencedFileID, path); - SetTagValue(record, DCM_ReferencedSOPClassUIDInFile, sopClassUid); - SetTagValue(record, DCM_ReferencedSOPInstanceUIDInFile, sopInstanceUid); - SetTagValue(record, DCM_ReferencedTransferSyntaxUIDInFile, transferSyntaxUid); - } - - - - bool CreateResource(DcmDirectoryRecord*& target, - ResourceType level, - ParsedDicomFile& dicom, - const char* filename, - const char* path) - { - DcmDataset& dataset = *dicom.GetDcmtkObject().getDataset(); - - bool hasCodeExtensions; - Encoding encoding = dicom.DetectEncoding(hasCodeExtensions); - - bool found; - std::string id; - E_DirRecType type; - - switch (level) - { - case ResourceType_Patient: - if (!GetUtf8TagValue(id, dataset, encoding, hasCodeExtensions, DCM_PatientID)) - { - // Be tolerant about missing patient ID. Fixes issue #124 - // (GET /studies/ID/media fails for certain dicom file). - id = ""; - } - - found = true; - type = ERT_Patient; - break; - - case ResourceType_Study: - found = GetUtf8TagValue(id, dataset, encoding, hasCodeExtensions, DCM_StudyInstanceUID); - type = ERT_Study; - break; - - case ResourceType_Series: - found = GetUtf8TagValue(id, dataset, encoding, hasCodeExtensions, DCM_SeriesInstanceUID); - type = ERT_Series; - break; - - case ResourceType_Instance: - found = GetUtf8TagValue(id, dataset, encoding, hasCodeExtensions, DCM_SOPInstanceUID); - type = ERT_Image; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - if (!found) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - IndexKey key = std::make_pair(level, std::string(id.c_str())); - Index::iterator it = index_.find(key); - - if (it != index_.end()) - { - target = it->second; - return false; // Already existing - } - - std::unique_ptr record(new DcmDirectoryRecord(type, NULL, filename)); - - switch (level) - { - case ResourceType_Patient: - FillPatient(*record, dataset, encoding, hasCodeExtensions); - break; - - case ResourceType_Study: - FillStudy(*record, dataset, encoding, hasCodeExtensions); - break; - - case ResourceType_Series: - FillSeries(*record, dataset, encoding, hasCodeExtensions); - break; - - case ResourceType_Instance: - FillInstance(*record, dataset, encoding, hasCodeExtensions, *dicom.GetDcmtkObject().getMetaInfo(), path); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - CopyStringType1C(*record, dataset, encoding, hasCodeExtensions, DCM_SpecificCharacterSet); - - target = record.get(); - GetRoot().insertSub(record.release()); - index_[key] = target; - - return true; // Newly created - } - - void Read(std::string& s) - { - if (!GetDicomDir().write(DICOMDIR_DEFAULT_TRANSFERSYNTAX, - EET_UndefinedLength /*encodingType*/, - EGL_withoutGL /*groupLength*/).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - - file_.Read(s); - } - - void SetFileSetId(const std::string& id) - { - dir_.reset(NULL); - fileSetId_ = id; - } - }; - - - DicomDirWriter::DicomDirWriter() : pimpl_(new PImpl) - { - } - - void DicomDirWriter::SetUtcUsed(bool utc) - { - pimpl_->SetUtcUsed(utc); - } - - bool DicomDirWriter::IsUtcUsed() const - { - return pimpl_->IsUtcUsed(); - } - - void DicomDirWriter::SetFileSetId(const std::string& id) - { - pimpl_->SetFileSetId(id); - } - - void DicomDirWriter::Add(const std::string& directory, - const std::string& filename, - ParsedDicomFile& dicom) - { - std::string path; - if (directory.empty()) - { - path = filename; - } - else - { - if (directory[directory.length() - 1] == '/' || - directory[directory.length() - 1] == '\\') - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - path = directory + '\\' + filename; - } - - DcmDirectoryRecord* instance; - bool isNewInstance = pimpl_->CreateResource(instance, ResourceType_Instance, dicom, filename.c_str(), path.c_str()); - if (isNewInstance) - { - DcmDirectoryRecord* series; - bool isNewSeries = pimpl_->CreateResource(series, ResourceType_Series, dicom, filename.c_str(), NULL); - series->insertSub(instance); - - if (isNewSeries) - { - DcmDirectoryRecord* study; - bool isNewStudy = pimpl_->CreateResource(study, ResourceType_Study, dicom, filename.c_str(), NULL); - study->insertSub(series); - - if (isNewStudy) - { - DcmDirectoryRecord* patient; - pimpl_->CreateResource(patient, ResourceType_Patient, dicom, filename.c_str(), NULL); - patient->insertSub(study); - } - } - } - } - - void DicomDirWriter::Encode(std::string& target) - { - pimpl_->Read(target); - } - - - void DicomDirWriter::EnableExtendedSopClass(bool enable) - { - pimpl_->EnableExtendedSopClass(enable); - } - - - bool DicomDirWriter::IsExtendedSopClass() const - { - return pimpl_->IsExtendedSopClass(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomDirWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ParsedDicomFile.h" - -#include - -namespace Orthanc -{ - class DicomDirWriter : public boost::noncopyable - { - private: - class PImpl; - boost::shared_ptr pimpl_; - - public: - DicomDirWriter(); - - void SetUtcUsed(bool utc); - - bool IsUtcUsed() const; - - void SetFileSetId(const std::string& id); - - void Add(const std::string& directory, - const std::string& filename, - ParsedDicomFile& dicom); - - void Encode(std::string& target); - - void EnableExtendedSopClass(bool enable); - - bool IsExtendedSopClass() const; - }; - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1522 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomModification.h" - -#include "../Compatibility.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../SerializationToolbox.h" -#include "FromDcmtkBridge.h" -#include "ITagVisitor.h" - -#include // For std::unique_ptr - - -static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2008 = - "Orthanc " ORTHANC_VERSION " - PS 3.15-2008 Table E.1-1"; - -static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2017c = - "Orthanc " ORTHANC_VERSION " - PS 3.15-2017c Table E.1-1 Basic Profile"; - -namespace Orthanc -{ - class DicomModification::RelationshipsVisitor : public ITagVisitor - { - private: - DicomModification& that_; - - bool IsEnabled(const DicomTag& tag) const - { - return (!that_.IsCleared(tag) && - !that_.IsRemoved(tag) && - !that_.IsReplaced(tag)); - } - - void RemoveIfEnabled(ParsedDicomFile& dicom, - const DicomTag& tag) const - { - if (IsEnabled(tag)) - { - dicom.Remove(tag); - } - } - - - public: - RelationshipsVisitor(DicomModification& that) : - that_(that) - { - } - - virtual void VisitNotSupported(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr) - { - } - - virtual void VisitEmptySequence(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag) - { - } - - virtual void VisitBinary(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const void* data, - size_t size) - { - } - - virtual void VisitIntegers(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) - { - } - - virtual void VisitDoubles(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& value) - { - } - - virtual void VisitAttributes(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - const std::vector& value) - { - } - - virtual Action VisitString(std::string& newValue, - const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::string& value) - { - if (!IsEnabled(tag)) - { - return Action_None; - } - else if (parentTags.size() == 2 && - parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && - parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && - tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID) - { - // in RT-STRUCT, this ReferencedSOPInstanceUID is actually referencing a StudyInstanceUID !! - // (observed in many data sets including: https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) - // tested in test_anonymize_relationships_5 - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Study); - return Action_Replace; - } - else if (tag == DICOM_TAG_FRAME_OF_REFERENCE_UID || - tag == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID || - tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID || - tag == DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Instance); - return Action_Replace; - } - else if (parentTags.size() == 1 && - parentTags[0] == DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE && - tag == DICOM_TAG_STUDY_INSTANCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Study); - return Action_Replace; - } - else if (parentTags.size() == 2 && - parentTags[0] == DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE && - parentTags[1] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE && - tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); - return Action_Replace; - } - else if (parentTags.size() == 3 && - parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && - parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && - parentTags[2] == DICOM_TAG_RT_REFERENCED_SERIES_SEQUENCE && - tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); - return Action_Replace; - } - else if (parentTags.size() == 1 && - parentTags[0] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE && - tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); - return Action_Replace; - } - else - { - return Action_None; - } - } - - void RemoveRelationships(ParsedDicomFile& dicom) const - { - // Sequences containing the UID relationships - RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_IMAGE_SEQUENCE); - RemoveIfEnabled(dicom, DICOM_TAG_SOURCE_IMAGE_SEQUENCE); - - // Individual tags - RemoveIfEnabled(dicom, DICOM_TAG_FRAME_OF_REFERENCE_UID); - - // The tags below should never occur at the first level of the - // hierarchy, but remove them anyway - RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID); - RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_SOP_INSTANCE_UID); - RemoveIfEnabled(dicom, DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID); - } - }; - - - bool DicomModification::CancelReplacement(const DicomTag& tag) - { - Replacements::iterator it = replacements_.find(tag); - - if (it != replacements_.end()) - { - delete it->second; - replacements_.erase(it); - return true; - } - else - { - return false; - } - } - - - void DicomModification::ReplaceInternal(const DicomTag& tag, - const Json::Value& value) - { - Replacements::iterator it = replacements_.find(tag); - - if (it != replacements_.end()) - { - delete it->second; - it->second = NULL; // In the case of an exception during the clone - it->second = new Json::Value(value); // Clone - } - else - { - replacements_[tag] = new Json::Value(value); // Clone - } - } - - - void DicomModification::ClearReplacements() - { - for (Replacements::iterator it = replacements_.begin(); - it != replacements_.end(); ++it) - { - delete it->second; - } - - replacements_.clear(); - } - - - void DicomModification::MarkNotOrthancAnonymization() - { - Replacements::iterator it = replacements_.find(DICOM_TAG_DEIDENTIFICATION_METHOD); - - if (it != replacements_.end() && - (it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2008 || - it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2017c)) - { - delete it->second; - replacements_.erase(it); - } - } - - void DicomModification::RegisterMappedDicomIdentifier(const std::string& original, - const std::string& mapped, - ResourceType level) - { - UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); - - if (previous == uidMap_.end()) - { - uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); - } - } - - std::string DicomModification::MapDicomIdentifier(const std::string& original, - ResourceType level) - { - std::string mapped; - - UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); - - if (previous == uidMap_.end()) - { - if (identifierGenerator_ == NULL) - { - mapped = FromDcmtkBridge::GenerateUniqueIdentifier(level); - } - else - { - if (!identifierGenerator_->Apply(mapped, original, level, currentSource_)) - { - throw OrthancException(ErrorCode_InternalError, - "Unable to generate an anonymized ID"); - } - } - - uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); - } - else - { - mapped = previous->second; - } - - return mapped; - } - - - void DicomModification::MapDicomTags(ParsedDicomFile& dicom, - ResourceType level) - { - std::unique_ptr tag; - - switch (level) - { - case ResourceType_Study: - tag.reset(new DicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); - break; - - case ResourceType_Series: - tag.reset(new DicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); - break; - - case ResourceType_Instance: - tag.reset(new DicomTag(DICOM_TAG_SOP_INSTANCE_UID)); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::string original; - if (!dicom.GetTagValue(original, *tag)) - { - original = ""; - } - - std::string mapped = MapDicomIdentifier(Toolbox::StripSpaces(original), level); - - dicom.Replace(*tag, mapped, - false /* don't try and decode data URI scheme for UIDs */, - DicomReplaceMode_InsertIfAbsent, privateCreator_); - } - - - DicomModification::DicomModification() : - removePrivateTags_(false), - level_(ResourceType_Instance), - allowManualIdentifiers_(true), - keepStudyInstanceUid_(false), - keepSeriesInstanceUid_(false), - keepSopInstanceUid_(false), - updateReferencedRelationships_(true), - isAnonymization_(false), - //privateCreator_("PrivateCreator"), - identifierGenerator_(NULL) - { - } - - DicomModification::~DicomModification() - { - ClearReplacements(); - } - - void DicomModification::Keep(const DicomTag& tag) - { - bool wasRemoved = IsRemoved(tag); - bool wasCleared = IsCleared(tag); - - removals_.erase(tag); - clearings_.erase(tag); - - bool wasReplaced = CancelReplacement(tag); - - if (tag == DICOM_TAG_STUDY_INSTANCE_UID) - { - keepStudyInstanceUid_ = true; - } - else if (tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - keepSeriesInstanceUid_ = true; - } - else if (tag == DICOM_TAG_SOP_INSTANCE_UID) - { - keepSopInstanceUid_ = true; - } - else if (tag.IsPrivate()) - { - privateTagsToKeep_.insert(tag); - } - else if (!wasRemoved && - !wasReplaced && - !wasCleared) - { - LOG(WARNING) << "Marking this tag as to be kept has no effect: " << tag.Format(); - } - - MarkNotOrthancAnonymization(); - } - - void DicomModification::Remove(const DicomTag& tag) - { - removals_.insert(tag); - clearings_.erase(tag); - CancelReplacement(tag); - privateTagsToKeep_.erase(tag); - - MarkNotOrthancAnonymization(); - } - - void DicomModification::Clear(const DicomTag& tag) - { - removals_.erase(tag); - clearings_.insert(tag); - CancelReplacement(tag); - privateTagsToKeep_.erase(tag); - - MarkNotOrthancAnonymization(); - } - - bool DicomModification::IsRemoved(const DicomTag& tag) const - { - return removals_.find(tag) != removals_.end(); - } - - bool DicomModification::IsCleared(const DicomTag& tag) const - { - return clearings_.find(tag) != clearings_.end(); - } - - void DicomModification::Replace(const DicomTag& tag, - const Json::Value& value, - bool safeForAnonymization) - { - clearings_.erase(tag); - removals_.erase(tag); - privateTagsToKeep_.erase(tag); - ReplaceInternal(tag, value); - - if (!safeForAnonymization) - { - MarkNotOrthancAnonymization(); - } - } - - - bool DicomModification::IsReplaced(const DicomTag& tag) const - { - return replacements_.find(tag) != replacements_.end(); - } - - const Json::Value& DicomModification::GetReplacement(const DicomTag& tag) const - { - Replacements::const_iterator it = replacements_.find(tag); - - if (it == replacements_.end()) - { - throw OrthancException(ErrorCode_InexistentItem); - } - else - { - return *it->second; - } - } - - - std::string DicomModification::GetReplacementAsString(const DicomTag& tag) const - { - const Json::Value& json = GetReplacement(tag); - - if (json.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - else - { - return json.asString(); - } - } - - - void DicomModification::SetRemovePrivateTags(bool removed) - { - removePrivateTags_ = removed; - - if (!removed) - { - MarkNotOrthancAnonymization(); - } - } - - void DicomModification::SetLevel(ResourceType level) - { - uidMap_.clear(); - level_ = level; - - if (level != ResourceType_Patient) - { - MarkNotOrthancAnonymization(); - } - } - - - void DicomModification::SetupAnonymization2008() - { - // This is Table E.1-1 from PS 3.15-2008 - DICOM Part 15: Security and System Management Profiles - // https://raw.githubusercontent.com/jodogne/dicom-specification/master/2008/08_15pu.pdf - - removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID - //removals_.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID => set in Apply() - removals_.insert(DicomTag(0x0008, 0x0050)); // Accession Number - removals_.insert(DicomTag(0x0008, 0x0080)); // Institution Name - removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address - removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name - removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address - removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers - removals_.insert(DicomTag(0x0008, 0x1010)); // Station Name - removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description - removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description - removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name - removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record - removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name - removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study - removals_.insert(DicomTag(0x0008, 0x1070)); // Operators' Name - removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description - //removals_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID => RelationshipsVisitor - removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description - //removals_.insert(DicomTag(0x0010, 0x0010)); // Patient's Name => cf. below (*) - //removals_.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) - removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date - removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time - removals_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex - removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient Ids - removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names - removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age - removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size - removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight - removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator - removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group - removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation - removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History - removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments - removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number - removals_.insert(DicomTag(0x0018, 0x1030)); // Protocol Name - //removals_.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => set in Apply() - //removals_.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => set in Apply() - removals_.insert(DicomTag(0x0020, 0x0010)); // Study ID - //removals_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID => cf. RelationshipsVisitor - removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments - removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence - removals_.insert(DicomTag(0x0040, 0xa124)); // UID - removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence - removals_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID - //removals_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID => RelationshipsVisitor - //removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID => RelationshipsVisitor - - // Some more removals (from the experience of DICOM files at the CHU of Liege) - removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address - removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician - removals_.insert(DicomTag(0x0010, 0x2154)); // PatientTelephoneNumbers - removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts - - // Set the DeidentificationMethod tag - ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2008); - } - - - void DicomModification::SetupAnonymization2017c() - { - /** - * This is Table E.1-1 from PS 3.15-2017c (DICOM Part 15: Security - * and System Management Profiles), "basic profile" column. It was - * generated automatically with the - * "../Resources/GenerateAnonymizationProfile.py" script. - * https://raw.githubusercontent.com/jodogne/dicom-specification/master/2017c/part15.pdf - **/ - - // TODO: (50xx,xxxx) with rule X // Curve Data - // TODO: (60xx,3000) with rule X // Overlay Data - // TODO: (60xx,4000) with rule X // Overlay Comments - // Tag (0x0008, 0x0018) is set in Apply() /* U */ // SOP Instance UID - // Tag (0x0008, 0x1140) => RelationshipsVisitor /* X/Z/U* */ // Referenced Image Sequence - // Tag (0x0008, 0x1155) => RelationshipsVisitor /* U */ // Referenced SOP Instance UID - // Tag (0x0008, 0x2112) => RelationshipsVisitor /* X/Z/U* */ // Source Image Sequence - // Tag (0x0010, 0x0010) is set below (*) /* Z */ // Patient's Name - // Tag (0x0010, 0x0020) is set below (*) /* Z */ // Patient ID - // Tag (0x0020, 0x000d) is set in Apply() /* U */ // Study Instance UID - // Tag (0x0020, 0x000e) is set in Apply() /* U */ // Series Instance UID - // Tag (0x0020, 0x0052) => RelationshipsVisitor /* U */ // Frame of Reference UID - // Tag (0x3006, 0x0024) => RelationshipsVisitor /* U */ // Referenced Frame of Reference UID - // Tag (0x3006, 0x00c2) => RelationshipsVisitor /* U */ // Related Frame of Reference UID - clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date - clearings_.insert(DicomTag(0x0008, 0x0023)); /* Z/D */ // Content Date - clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time - clearings_.insert(DicomTag(0x0008, 0x0033)); /* Z/D */ // Content Time - clearings_.insert(DicomTag(0x0008, 0x0050)); // Accession Number - clearings_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name - clearings_.insert(DicomTag(0x0008, 0x009c)); // Consulting Physician's Name - clearings_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date - clearings_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex - clearings_.insert(DicomTag(0x0018, 0x0010)); /* Z/D */ // Contrast Bolus Agent - clearings_.insert(DicomTag(0x0020, 0x0010)); // Study ID - clearings_.insert(DicomTag(0x0040, 0x1101)); /* D */ // Person Identification Code Sequence - clearings_.insert(DicomTag(0x0040, 0x2016)); // Placer Order Number / Imaging Service Request - clearings_.insert(DicomTag(0x0040, 0x2017)); // Filler Order Number / Imaging Service Request - clearings_.insert(DicomTag(0x0040, 0xa073)); /* D */ // Verifying Observer Sequence - clearings_.insert(DicomTag(0x0040, 0xa075)); /* D */ // Verifying Observer Name - clearings_.insert(DicomTag(0x0040, 0xa088)); // Verifying Observer Identification Code Sequence - clearings_.insert(DicomTag(0x0040, 0xa123)); /* D */ // Person Name - clearings_.insert(DicomTag(0x0070, 0x0001)); /* D */ // Graphic Annotation Sequence - clearings_.insert(DicomTag(0x0070, 0x0084)); // Content Creator's Name - removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID - removals_.insert(DicomTag(0x0000, 0x1001)); /* TODO UID */ // Requested SOP Instance UID - removals_.insert(DicomTag(0x0002, 0x0003)); /* TODO UID */ // Media Storage SOP Instance UID - removals_.insert(DicomTag(0x0004, 0x1511)); /* TODO UID */ // Referenced SOP Instance UID in File - removals_.insert(DicomTag(0x0008, 0x0014)); /* TODO UID */ // Instance Creator UID - removals_.insert(DicomTag(0x0008, 0x0015)); // Instance Coercion DateTime - removals_.insert(DicomTag(0x0008, 0x0021)); /* X/D */ // Series Date - removals_.insert(DicomTag(0x0008, 0x0022)); /* X/Z */ // Acquisition Date - removals_.insert(DicomTag(0x0008, 0x0024)); // Overlay Date - removals_.insert(DicomTag(0x0008, 0x0025)); // Curve Date - removals_.insert(DicomTag(0x0008, 0x002a)); /* X/D */ // Acquisition DateTime - removals_.insert(DicomTag(0x0008, 0x0031)); /* X/D */ // Series Time - removals_.insert(DicomTag(0x0008, 0x0032)); /* X/Z */ // Acquisition Time - removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time - removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time - removals_.insert(DicomTag(0x0008, 0x0058)); /* TODO UID */ // Failed SOP Instance UID List - removals_.insert(DicomTag(0x0008, 0x0080)); /* X/Z/D */ // Institution Name - removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address - removals_.insert(DicomTag(0x0008, 0x0082)); /* X/Z/D */ // Institution Code Sequence - removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address - removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers - removals_.insert(DicomTag(0x0008, 0x0096)); // Referring Physician Identification Sequence - removals_.insert(DicomTag(0x0008, 0x009d)); // Consulting Physician Identification Sequence - removals_.insert(DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC - removals_.insert(DicomTag(0x0008, 0x1010)); /* X/Z/D */ // Station Name - removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description - removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description - removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name - removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record - removals_.insert(DicomTag(0x0008, 0x1049)); // Physician(s) of Record Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name - removals_.insert(DicomTag(0x0008, 0x1052)); // Performing Physician Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study - removals_.insert(DicomTag(0x0008, 0x1062)); // Physician(s) Reading Study Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1070)); /* X/Z/D */ // Operators' Name - removals_.insert(DicomTag(0x0008, 0x1072)); /* X/D */ // Operators' Identification Sequence - removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description - removals_.insert(DicomTag(0x0008, 0x1084)); // Admitting Diagnoses Code Sequence - removals_.insert(DicomTag(0x0008, 0x1110)); /* X/Z */ // Referenced Study Sequence - removals_.insert(DicomTag(0x0008, 0x1111)); /* X/Z/D */ // Referenced Performed Procedure Step Sequence - removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence - removals_.insert(DicomTag(0x0008, 0x1195)); /* TODO UID */ // Transaction UID - removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description - removals_.insert(DicomTag(0x0008, 0x3010)); /* TODO UID */ // Irradiation Event UID - removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments - removals_.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID - removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time - removals_.insert(DicomTag(0x0010, 0x0050)); // Patient's Insurance Plan Code Sequence - removals_.insert(DicomTag(0x0010, 0x0101)); // Patient's Primary Language Code Sequence - removals_.insert(DicomTag(0x0010, 0x0102)); // Patient's Primary Language Modifier Code Sequence - removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient IDs - removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names - removals_.insert(DicomTag(0x0010, 0x1002)); // Other Patient IDs Sequence - removals_.insert(DicomTag(0x0010, 0x1005)); // Patient's Birth Name - removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age - removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size - removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight - removals_.insert(DicomTag(0x0010, 0x1040)); // Patient Address - removals_.insert(DicomTag(0x0010, 0x1050)); // Insurance Plan Identification - removals_.insert(DicomTag(0x0010, 0x1060)); // Patient's Mother's Birth Name - removals_.insert(DicomTag(0x0010, 0x1080)); // Military Rank - removals_.insert(DicomTag(0x0010, 0x1081)); // Branch of Service - removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator - removals_.insert(DicomTag(0x0010, 0x1100)); // Referenced Patient Photo Sequence - removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts - removals_.insert(DicomTag(0x0010, 0x2110)); // Allergies - removals_.insert(DicomTag(0x0010, 0x2150)); // Country of Residence - removals_.insert(DicomTag(0x0010, 0x2152)); // Region of Residence - removals_.insert(DicomTag(0x0010, 0x2154)); // Patient's Telephone Numbers - removals_.insert(DicomTag(0x0010, 0x2155)); // Patient's Telecom Information - removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group - removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation - removals_.insert(DicomTag(0x0010, 0x21a0)); // Smoking Status - removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History - removals_.insert(DicomTag(0x0010, 0x21c0)); // Pregnancy Status - removals_.insert(DicomTag(0x0010, 0x21d0)); // Last Menstrual Date - removals_.insert(DicomTag(0x0010, 0x21f0)); // Patient's Religious Preference - removals_.insert(DicomTag(0x0010, 0x2203)); /* X/Z */ // Patient Sex Neutered - removals_.insert(DicomTag(0x0010, 0x2297)); // Responsible Person - removals_.insert(DicomTag(0x0010, 0x2299)); // Responsible Organization - removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments - removals_.insert(DicomTag(0x0018, 0x1000)); /* X/Z/D */ // Device Serial Number - removals_.insert(DicomTag(0x0018, 0x1002)); /* TODO UID */ // Device UID - removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID - removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID - removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID - removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID - removals_.insert(DicomTag(0x0018, 0x1030)); /* X/D */ // Protocol Name - removals_.insert(DicomTag(0x0018, 0x1400)); /* X/D */ // Acquisition Device Processing Description - removals_.insert(DicomTag(0x0018, 0x2042)); /* TODO UID */ // Target UID - removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments - removals_.insert(DicomTag(0x0018, 0x700a)); /* X/D */ // Detector ID - removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description - removals_.insert(DicomTag(0x0018, 0x9516)); /* X/D */ // Start Acquisition DateTime - removals_.insert(DicomTag(0x0018, 0x9517)); /* X/D */ // End Acquisition DateTime - removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description - removals_.insert(DicomTag(0x0020, 0x0200)); /* TODO UID */ // Synchronization Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID - removals_.insert(DicomTag(0x0020, 0x3404)); // Modifying Device Manufacturer - removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description - removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments - removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments - removals_.insert(DicomTag(0x0020, 0x9161)); /* TODO UID */ // Concatenation UID - removals_.insert(DicomTag(0x0020, 0x9164)); /* TODO UID */ // Dimension Organization UID - removals_.insert(DicomTag(0x0028, 0x1199)); /* TODO UID */ // Palette Color Lookup Table UID - removals_.insert(DicomTag(0x0028, 0x1214)); /* TODO UID */ // Large Palette Color Lookup Table UID - removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments - removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer - removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location - removals_.insert(DicomTag(0x0032, 0x1021)); // Scheduled Study Location AE Title - removals_.insert(DicomTag(0x0032, 0x1030)); // Reason for Study - removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician - removals_.insert(DicomTag(0x0032, 0x1033)); // Requesting Service - removals_.insert(DicomTag(0x0032, 0x1060)); /* X/Z */ // Requested Procedure Description - removals_.insert(DicomTag(0x0032, 0x1070)); // Requested Contrast Agent - removals_.insert(DicomTag(0x0032, 0x4000)); // Study Comments - removals_.insert(DicomTag(0x0038, 0x0004)); // Referenced Patient Alias Sequence - removals_.insert(DicomTag(0x0038, 0x0010)); // Admission ID - removals_.insert(DicomTag(0x0038, 0x0011)); // Issuer of Admission ID - removals_.insert(DicomTag(0x0038, 0x001e)); // Scheduled Patient Institution Residence - removals_.insert(DicomTag(0x0038, 0x0020)); // Admitting Date - removals_.insert(DicomTag(0x0038, 0x0021)); // Admitting Time - removals_.insert(DicomTag(0x0038, 0x0040)); // Discharge Diagnosis Description - removals_.insert(DicomTag(0x0038, 0x0050)); // Special Needs - removals_.insert(DicomTag(0x0038, 0x0060)); // Service Episode ID - removals_.insert(DicomTag(0x0038, 0x0061)); // Issuer of Service Episode ID - removals_.insert(DicomTag(0x0038, 0x0062)); // Service Episode Description - removals_.insert(DicomTag(0x0038, 0x0300)); // Current Patient Location - removals_.insert(DicomTag(0x0038, 0x0400)); // Patient's Institution Residence - removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State - removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments - removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title - removals_.insert(DicomTag(0x0040, 0x0002)); // Scheduled Procedure Step Start Date - removals_.insert(DicomTag(0x0040, 0x0003)); // Scheduled Procedure Step Start Time - removals_.insert(DicomTag(0x0040, 0x0004)); // Scheduled Procedure Step End Date - removals_.insert(DicomTag(0x0040, 0x0005)); // Scheduled Procedure Step End Time - removals_.insert(DicomTag(0x0040, 0x0006)); // Scheduled Performing Physician Name - removals_.insert(DicomTag(0x0040, 0x0007)); // Scheduled Procedure Step Description - removals_.insert(DicomTag(0x0040, 0x000b)); // Scheduled Performing Physician Identification Sequence - removals_.insert(DicomTag(0x0040, 0x0010)); // Scheduled Station Name - removals_.insert(DicomTag(0x0040, 0x0011)); // Scheduled Procedure Step Location - removals_.insert(DicomTag(0x0040, 0x0012)); // Pre-Medication - removals_.insert(DicomTag(0x0040, 0x0241)); // Performed Station AE Title - removals_.insert(DicomTag(0x0040, 0x0242)); // Performed Station Name - removals_.insert(DicomTag(0x0040, 0x0243)); // Performed Location - removals_.insert(DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date - removals_.insert(DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time - removals_.insert(DicomTag(0x0040, 0x0250)); // Performed Procedure Step End Date - removals_.insert(DicomTag(0x0040, 0x0251)); // Performed Procedure Step End Time - removals_.insert(DicomTag(0x0040, 0x0253)); // Performed Procedure Step ID - removals_.insert(DicomTag(0x0040, 0x0254)); // Performed Procedure Step Description - removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence - removals_.insert(DicomTag(0x0040, 0x0280)); // Comments on the Performed Procedure Step - removals_.insert(DicomTag(0x0040, 0x0555)); // Acquisition Context Sequence - removals_.insert(DicomTag(0x0040, 0x1001)); // Requested Procedure ID - removals_.insert(DicomTag(0x0040, 0x1004)); // Patient Transport Arrangements - removals_.insert(DicomTag(0x0040, 0x1005)); // Requested Procedure Location - removals_.insert(DicomTag(0x0040, 0x1010)); // Names of Intended Recipient of Results - removals_.insert(DicomTag(0x0040, 0x1011)); // Intended Recipients of Results Identification Sequence - removals_.insert(DicomTag(0x0040, 0x1102)); // Person Address - removals_.insert(DicomTag(0x0040, 0x1103)); // Person's Telephone Numbers - removals_.insert(DicomTag(0x0040, 0x1104)); // Person's Telecom Information - removals_.insert(DicomTag(0x0040, 0x1400)); // Requested Procedure Comments - removals_.insert(DicomTag(0x0040, 0x2001)); // Reason for the Imaging Service Request - removals_.insert(DicomTag(0x0040, 0x2008)); // Order Entered By - removals_.insert(DicomTag(0x0040, 0x2009)); // Order Enterer Location - removals_.insert(DicomTag(0x0040, 0x2010)); // Order Callback Phone Number - removals_.insert(DicomTag(0x0040, 0x2011)); // Order Callback Telecom Information - removals_.insert(DicomTag(0x0040, 0x2400)); // Imaging Service Request Comments - removals_.insert(DicomTag(0x0040, 0x3001)); // Confidentiality Constraint on Patient Data Description - removals_.insert(DicomTag(0x0040, 0x4005)); // Scheduled Procedure Step Start DateTime - removals_.insert(DicomTag(0x0040, 0x4010)); // Scheduled Procedure Step Modification DateTime - removals_.insert(DicomTag(0x0040, 0x4011)); // Expected Completion DateTime - removals_.insert(DicomTag(0x0040, 0x4023)); /* TODO UID */ // Referenced General Purpose Scheduled Procedure Step Transaction UID - removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence - removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence - removals_.insert(DicomTag(0x0040, 0x4028)); // Performed Station Name Code Sequence - removals_.insert(DicomTag(0x0040, 0x4030)); // Performed Station Geographic Location Code Sequence - removals_.insert(DicomTag(0x0040, 0x4034)); // Scheduled Human Performers Sequence - removals_.insert(DicomTag(0x0040, 0x4035)); // Actual Human Performers Sequence - removals_.insert(DicomTag(0x0040, 0x4036)); // Human Performers Organization - removals_.insert(DicomTag(0x0040, 0x4037)); // Human Performers Name - removals_.insert(DicomTag(0x0040, 0x4050)); // Performed Procedure Step Start DateTime - removals_.insert(DicomTag(0x0040, 0x4051)); // Performed Procedure Step End DateTime - removals_.insert(DicomTag(0x0040, 0x4052)); // Procedure Step Cancellation DateTime - removals_.insert(DicomTag(0x0040, 0xa027)); // Verifying Organization - removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence - removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence - removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence - removals_.insert(DicomTag(0x0040, 0xa124)); /* TODO UID */ // UID - removals_.insert(DicomTag(0x0040, 0xa171)); /* TODO UID */ // Observation UID - removals_.insert(DicomTag(0x0040, 0xa172)); /* TODO UID */ // Referenced Observation UID (Trial) - removals_.insert(DicomTag(0x0040, 0xa192)); // Observation Date (Trial) - removals_.insert(DicomTag(0x0040, 0xa193)); // Observation Time (Trial) - removals_.insert(DicomTag(0x0040, 0xa307)); // Current Observer (Trial) - removals_.insert(DicomTag(0x0040, 0xa352)); // Verbal Source (Trial) - removals_.insert(DicomTag(0x0040, 0xa353)); // Address (Trial) - removals_.insert(DicomTag(0x0040, 0xa354)); // Telephone Number (Trial) - removals_.insert(DicomTag(0x0040, 0xa358)); // Verbal Source Identifier Code Sequence (Trial) - removals_.insert(DicomTag(0x0040, 0xa402)); /* TODO UID */ // Observation Subject UID (Trial) - removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence - removals_.insert(DicomTag(0x0040, 0xdb0c)); /* TODO UID */ // Template Extension Organization UID - removals_.insert(DicomTag(0x0040, 0xdb0d)); /* TODO UID */ // Template Extension Creator UID - removals_.insert(DicomTag(0x0062, 0x0021)); /* TODO UID */ // Tracking UID - removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence - removals_.insert(DicomTag(0x0070, 0x031a)); /* TODO UID */ // Fiducial UID - removals_.insert(DicomTag(0x0070, 0x1101)); /* TODO UID */ // Presentation Display Collection UID - removals_.insert(DicomTag(0x0070, 0x1102)); /* TODO UID */ // Presentation Sequence Collection UID - removals_.insert(DicomTag(0x0088, 0x0140)); /* TODO UID */ // Storage Media File-set UID - removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence(see Note 12) - removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title - removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject - removals_.insert(DicomTag(0x0088, 0x0910)); // Topic Author - removals_.insert(DicomTag(0x0088, 0x0912)); // Topic Keywords - removals_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID - removals_.insert(DicomTag(0x0400, 0x0402)); // Referenced Digital Signature Sequence - removals_.insert(DicomTag(0x0400, 0x0403)); // Referenced SOP Instance MAC Sequence - removals_.insert(DicomTag(0x0400, 0x0404)); // MAC - removals_.insert(DicomTag(0x0400, 0x0550)); // Modified Attributes Sequence - removals_.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence - removals_.insert(DicomTag(0x2030, 0x0020)); // Text String - removals_.insert(DicomTag(0x3008, 0x0105)); // Source Serial Number - removals_.insert(DicomTag(0x300a, 0x0013)); /* TODO UID */ // Dose Reference UID - removals_.insert(DicomTag(0x300c, 0x0113)); // Reason for Omission Description - removals_.insert(DicomTag(0x300e, 0x0008)); /* X/Z */ // Reviewer Name - removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary - removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments - removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer - removals_.insert(DicomTag(0x4008, 0x0102)); // Interpretation Recorder - removals_.insert(DicomTag(0x4008, 0x010a)); // Interpretation Transcriber - removals_.insert(DicomTag(0x4008, 0x010b)); // Interpretation Text - removals_.insert(DicomTag(0x4008, 0x010c)); // Interpretation Author - removals_.insert(DicomTag(0x4008, 0x0111)); // Interpretation Approver Sequence - removals_.insert(DicomTag(0x4008, 0x0114)); // Physician Approving Interpretation - removals_.insert(DicomTag(0x4008, 0x0115)); // Interpretation Diagnosis Description - removals_.insert(DicomTag(0x4008, 0x0118)); // Results Distribution List Sequence - removals_.insert(DicomTag(0x4008, 0x0119)); // Distribution Name - removals_.insert(DicomTag(0x4008, 0x011a)); // Distribution Address - removals_.insert(DicomTag(0x4008, 0x0202)); // Interpretation ID Issuer - removals_.insert(DicomTag(0x4008, 0x0300)); // Impressions - removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments - removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signatures Sequence - removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding - - // Set the DeidentificationMethod tag - ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2017c); - } - - - void DicomModification::SetupAnonymization(DicomVersion version) - { - isAnonymization_ = true; - - removals_.clear(); - clearings_.clear(); - ClearReplacements(); - removePrivateTags_ = true; - level_ = ResourceType_Patient; - uidMap_.clear(); - privateTagsToKeep_.clear(); - - switch (version) - { - case DicomVersion_2008: - SetupAnonymization2008(); - break; - - case DicomVersion_2017c: - SetupAnonymization2017c(); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - // Set the PatientIdentityRemoved tag - ReplaceInternal(DicomTag(0x0012, 0x0062), "YES"); - - // (*) Choose a random patient name and ID - std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient); - ReplaceInternal(DICOM_TAG_PATIENT_ID, patientId); - ReplaceInternal(DICOM_TAG_PATIENT_NAME, patientId); - } - - void DicomModification::Apply(ParsedDicomFile& toModify) - { - // Check the request - assert(ResourceType_Patient + 1 == ResourceType_Study && - ResourceType_Study + 1 == ResourceType_Series && - ResourceType_Series + 1 == ResourceType_Instance); - - if (IsRemoved(DICOM_TAG_PATIENT_ID) || - IsRemoved(DICOM_TAG_STUDY_INSTANCE_UID) || - IsRemoved(DICOM_TAG_SERIES_INSTANCE_UID) || - IsRemoved(DICOM_TAG_SOP_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest); - } - - - // Sanity checks at the patient level - if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a patient, her PatientID is required to be modified"); - } - - if (!allowManualIdentifiers_) - { - if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a patient, the StudyInstanceUID cannot be manually modified"); - } - - if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a patient, the SeriesInstanceUID cannot be manually modified"); - } - - if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a patient, the SopInstanceUID cannot be manually modified"); - } - } - - - // Sanity checks at the study level - if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_PATIENT_ID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a study, the parent PatientID cannot be manually modified"); - } - - if (!allowManualIdentifiers_) - { - if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a study, the SeriesInstanceUID cannot be manually modified"); - } - - if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a study, the SopInstanceUID cannot be manually modified"); - } - } - - - // Sanity checks at the series level - if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_PATIENT_ID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the parent PatientID cannot be manually modified"); - } - - if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the parent StudyInstanceUID cannot be manually modified"); - } - - if (!allowManualIdentifiers_) - { - if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the SopInstanceUID cannot be manually modified"); - } - } - - - // Sanity checks at the instance level - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_PATIENT_ID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent PatientID cannot be manually modified"); - } - - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent StudyInstanceUID cannot be manually modified"); - } - - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); - } - - // (0) Create a summary of the source file, if a custom generator - // is provided - if (identifierGenerator_ != NULL) - { - toModify.ExtractDicomSummary(currentSource_); - } - - // (1) Make sure the relationships are updated with the ids that we force too - // i.e: an RT-STRUCT is referencing its own StudyInstanceUID - if (isAnonymization_ && updateReferencedRelationships_) - { - if (IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - std::string original; - std::string replacement = GetReplacementAsString(DICOM_TAG_STUDY_INSTANCE_UID); - toModify.GetTagValue(original, DICOM_TAG_STUDY_INSTANCE_UID); - RegisterMappedDicomIdentifier(original, replacement, ResourceType_Study); - } - - if (IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - std::string original; - std::string replacement = GetReplacementAsString(DICOM_TAG_SERIES_INSTANCE_UID); - toModify.GetTagValue(original, DICOM_TAG_SERIES_INSTANCE_UID); - RegisterMappedDicomIdentifier(original, replacement, ResourceType_Series); - } - - if (IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) - { - std::string original; - std::string replacement = GetReplacementAsString(DICOM_TAG_SOP_INSTANCE_UID); - toModify.GetTagValue(original, DICOM_TAG_SOP_INSTANCE_UID); - RegisterMappedDicomIdentifier(original, replacement, ResourceType_Instance); - } - } - - - // (2) Remove the private tags, if need be - if (removePrivateTags_) - { - toModify.RemovePrivateTags(privateTagsToKeep_); - } - - // (3) Clear the tags specified by the user - for (SetOfTags::const_iterator it = clearings_.begin(); - it != clearings_.end(); ++it) - { - toModify.Clear(*it, true /* only clear if the tag exists in the original file */); - } - - // (4) Remove the tags specified by the user - for (SetOfTags::const_iterator it = removals_.begin(); - it != removals_.end(); ++it) - { - toModify.Remove(*it); - } - - // (5) Replace the tags - for (Replacements::const_iterator it = replacements_.begin(); - it != replacements_.end(); ++it) - { - toModify.Replace(it->first, *it->second, true /* decode data URI scheme */, - DicomReplaceMode_InsertIfAbsent, privateCreator_); - } - - // (6) Update the DICOM identifiers - if (level_ <= ResourceType_Study && - !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - if (keepStudyInstanceUid_) - { - LOG(WARNING) << "Modifying a study while keeping its original StudyInstanceUID: This should be avoided!"; - } - else - { - MapDicomTags(toModify, ResourceType_Study); - } - } - - if (level_ <= ResourceType_Series && - !IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - if (keepSeriesInstanceUid_) - { - LOG(WARNING) << "Modifying a series while keeping its original SeriesInstanceUID: This should be avoided!"; - } - else - { - MapDicomTags(toModify, ResourceType_Series); - } - } - - if (level_ <= ResourceType_Instance && // Always true - !IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) - { - if (keepSopInstanceUid_) - { - LOG(WARNING) << "Modifying an instance while keeping its original SOPInstanceUID: This should be avoided!"; - } - else - { - MapDicomTags(toModify, ResourceType_Instance); - } - } - - // (7) Update the "referenced" relationships in the case of an anonymization - if (isAnonymization_) - { - RelationshipsVisitor visitor(*this); - - if (updateReferencedRelationships_) - { - toModify.Apply(visitor); - } - else - { - visitor.RemoveRelationships(toModify); - } - } - } - - - static bool IsDatabaseKey(const DicomTag& tag) - { - return (tag == DICOM_TAG_PATIENT_ID || - tag == DICOM_TAG_STUDY_INSTANCE_UID || - tag == DICOM_TAG_SERIES_INSTANCE_UID || - tag == DICOM_TAG_SOP_INSTANCE_UID); - } - - - static void ParseListOfTags(DicomModification& target, - const Json::Value& query, - DicomModification::TagOperation operation, - bool force) - { - if (!query.isArray()) - { - throw OrthancException(ErrorCode_BadRequest); - } - - for (Json::Value::ArrayIndex i = 0; i < query.size(); i++) - { - if (query[i].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest); - } - - std::string name = query[i].asString(); - - DicomTag tag = FromDcmtkBridge::ParseTag(name); - - if (!force && IsDatabaseKey(tag)) - { - throw OrthancException(ErrorCode_BadRequest, - "Marking tag \"" + name + "\" as to be " + - (operation == DicomModification::TagOperation_Keep ? "kept" : "removed") + - " requires the \"Force\" option to be set to true"); - } - - switch (operation) - { - case DicomModification::TagOperation_Keep: - target.Keep(tag); - VLOG(1) << "Keep: " << name << " " << tag; - break; - - case DicomModification::TagOperation_Remove: - target.Remove(tag); - VLOG(1) << "Remove: " << name << " " << tag; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - } - - - static void ParseReplacements(DicomModification& target, - const Json::Value& replacements, - bool force) - { - if (!replacements.isObject()) - { - throw OrthancException(ErrorCode_BadRequest); - } - - Json::Value::Members members = replacements.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - const Json::Value& value = replacements[name]; - - DicomTag tag = FromDcmtkBridge::ParseTag(name); - - if (!force && IsDatabaseKey(tag)) - { - throw OrthancException(ErrorCode_BadRequest, - "Marking tag \"" + name + "\" as to be replaced " + - "requires the \"Force\" option to be set to true"); - } - - target.Replace(tag, value, false); - - VLOG(1) << "Replace: " << name << " " << tag - << " == " << value.toStyledString(); - } - } - - - static bool GetBooleanValue(const std::string& member, - const Json::Value& json, - bool defaultValue) - { - if (!json.isMember(member)) - { - return defaultValue; - } - else if (json[member].type() == Json::booleanValue) - { - return json[member].asBool(); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Member \"" + member + "\" should be a Boolean value"); - } - } - - - void DicomModification::ParseModifyRequest(const Json::Value& request) - { - if (!request.isObject()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - bool force = GetBooleanValue("Force", request, false); - - if (GetBooleanValue("RemovePrivateTags", request, false)) - { - SetRemovePrivateTags(true); - } - - if (request.isMember("Remove")) - { - ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); - } - - if (request.isMember("Replace")) - { - ParseReplacements(*this, request["Replace"], force); - } - - // The "Keep" operation only makes sense for the tags - // StudyInstanceUID, SeriesInstanceUID and SOPInstanceUID. Avoid - // this feature as much as possible, as this breaks the DICOM - // model of the real world, except if you know exactly what - // you're doing! - if (request.isMember("Keep")) - { - ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force); - } - - // New in Orthanc 1.6.0 - if (request.isMember("PrivateCreator")) - { - privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); - } - } - - - void DicomModification::ParseAnonymizationRequest(bool& patientNameReplaced, - const Json::Value& request) - { - if (!request.isObject()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - bool force = GetBooleanValue("Force", request, false); - - // As of Orthanc 1.3.0, the default anonymization is done - // according to PS 3.15-2017c Table E.1-1 (basic profile) - DicomVersion version = DicomVersion_2017c; - if (request.isMember("DicomVersion")) - { - if (request["DicomVersion"].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - version = StringToDicomVersion(request["DicomVersion"].asString()); - } - } - - SetupAnonymization(version); - - std::string patientName = GetReplacementAsString(DICOM_TAG_PATIENT_NAME); - - if (GetBooleanValue("KeepPrivateTags", request, false)) - { - SetRemovePrivateTags(false); - } - - if (request.isMember("Remove")) - { - ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); - } - - if (request.isMember("Replace")) - { - ParseReplacements(*this, request["Replace"], force); - } - - if (request.isMember("Keep")) - { - ParseListOfTags(*this, request["Keep"], TagOperation_Keep, force); - } - - patientNameReplaced = (IsReplaced(DICOM_TAG_PATIENT_NAME) && - GetReplacement(DICOM_TAG_PATIENT_NAME) == patientName); - - // New in Orthanc 1.6.0 - if (request.isMember("PrivateCreator")) - { - privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); - } - } - - - - - static const char* REMOVE_PRIVATE_TAGS = "RemovePrivateTags"; - static const char* LEVEL = "Level"; - static const char* ALLOW_MANUAL_IDENTIFIERS = "AllowManualIdentifiers"; - static const char* KEEP_STUDY_INSTANCE_UID = "KeepStudyInstanceUID"; - static const char* KEEP_SERIES_INSTANCE_UID = "KeepSeriesInstanceUID"; - static const char* KEEP_SOP_INSTANCE_UID = "KeepSOPInstanceUID"; - static const char* UPDATE_REFERENCED_RELATIONSHIPS = "UpdateReferencedRelationships"; - static const char* IS_ANONYMIZATION = "IsAnonymization"; - static const char* REMOVALS = "Removals"; - static const char* CLEARINGS = "Clearings"; - static const char* PRIVATE_TAGS_TO_KEEP = "PrivateTagsToKeep"; - static const char* REPLACEMENTS = "Replacements"; - static const char* MAP_PATIENTS = "MapPatients"; - static const char* MAP_STUDIES = "MapStudies"; - static const char* MAP_SERIES = "MapSeries"; - static const char* MAP_INSTANCES = "MapInstances"; - static const char* PRIVATE_CREATOR = "PrivateCreator"; // New in Orthanc 1.6.0 - - void DicomModification::Serialize(Json::Value& value) const - { - if (identifierGenerator_ != NULL) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot serialize a DicomModification with a custom identifier generator"); - } - - value = Json::objectValue; - value[REMOVE_PRIVATE_TAGS] = removePrivateTags_; - value[LEVEL] = EnumerationToString(level_); - value[ALLOW_MANUAL_IDENTIFIERS] = allowManualIdentifiers_; - value[KEEP_STUDY_INSTANCE_UID] = keepStudyInstanceUid_; - value[KEEP_SERIES_INSTANCE_UID] = keepSeriesInstanceUid_; - value[KEEP_SOP_INSTANCE_UID] = keepSopInstanceUid_; - value[UPDATE_REFERENCED_RELATIONSHIPS] = updateReferencedRelationships_; - value[IS_ANONYMIZATION] = isAnonymization_; - value[PRIVATE_CREATOR] = privateCreator_; - - SerializationToolbox::WriteSetOfTags(value, removals_, REMOVALS); - SerializationToolbox::WriteSetOfTags(value, clearings_, CLEARINGS); - SerializationToolbox::WriteSetOfTags(value, privateTagsToKeep_, PRIVATE_TAGS_TO_KEEP); - - Json::Value& tmp = value[REPLACEMENTS]; - - tmp = Json::objectValue; - - for (Replacements::const_iterator it = replacements_.begin(); - it != replacements_.end(); ++it) - { - assert(it->second != NULL); - tmp[it->first.Format()] = *it->second; - } - - Json::Value& mapPatients = value[MAP_PATIENTS]; - Json::Value& mapStudies = value[MAP_STUDIES]; - Json::Value& mapSeries = value[MAP_SERIES]; - Json::Value& mapInstances = value[MAP_INSTANCES]; - - mapPatients = Json::objectValue; - mapStudies = Json::objectValue; - mapSeries = Json::objectValue; - mapInstances = Json::objectValue; - - for (UidMap::const_iterator it = uidMap_.begin(); it != uidMap_.end(); ++it) - { - Json::Value* tmp = NULL; - - switch (it->first.first) - { - case ResourceType_Patient: - tmp = &mapPatients; - break; - - case ResourceType_Study: - tmp = &mapStudies; - break; - - case ResourceType_Series: - tmp = &mapSeries; - break; - - case ResourceType_Instance: - tmp = &mapInstances; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - assert(tmp != NULL); - (*tmp) [it->first.second] = it->second; - } - } - - - void DicomModification::UnserializeUidMap(ResourceType level, - const Json::Value& serialized, - const char* field) - { - if (!serialized.isMember(field) || - serialized[field].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value::Members names = serialized[field].getMemberNames(); - - for (Json::Value::Members::const_iterator it = names.begin(); it != names.end(); ++it) - { - const Json::Value& value = serialized[field][*it]; - - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - uidMap_[std::make_pair(level, *it)] = value.asString(); - } - } - } - - - DicomModification::DicomModification(const Json::Value& serialized) : - identifierGenerator_(NULL) - { - removePrivateTags_ = SerializationToolbox::ReadBoolean(serialized, REMOVE_PRIVATE_TAGS); - level_ = StringToResourceType(SerializationToolbox::ReadString(serialized, LEVEL).c_str()); - allowManualIdentifiers_ = SerializationToolbox::ReadBoolean(serialized, ALLOW_MANUAL_IDENTIFIERS); - keepStudyInstanceUid_ = SerializationToolbox::ReadBoolean(serialized, KEEP_STUDY_INSTANCE_UID); - keepSeriesInstanceUid_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SERIES_INSTANCE_UID); - keepSopInstanceUid_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SOP_INSTANCE_UID); - updateReferencedRelationships_ = SerializationToolbox::ReadBoolean - (serialized, UPDATE_REFERENCED_RELATIONSHIPS); - isAnonymization_ = SerializationToolbox::ReadBoolean(serialized, IS_ANONYMIZATION); - - if (serialized.isMember(PRIVATE_CREATOR)) - { - privateCreator_ = SerializationToolbox::ReadString(serialized, PRIVATE_CREATOR); - } - - SerializationToolbox::ReadSetOfTags(removals_, serialized, REMOVALS); - SerializationToolbox::ReadSetOfTags(clearings_, serialized, CLEARINGS); - SerializationToolbox::ReadSetOfTags(privateTagsToKeep_, serialized, PRIVATE_TAGS_TO_KEEP); - - if (!serialized.isMember(REPLACEMENTS) || - serialized[REPLACEMENTS].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value::Members names = serialized[REPLACEMENTS].getMemberNames(); - - for (Json::Value::Members::const_iterator it = names.begin(); it != names.end(); ++it) - { - DicomTag tag(0, 0); - if (!DicomTag::ParseHexadecimal(tag, it->c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - const Json::Value& value = serialized[REPLACEMENTS][*it]; - replacements_.insert(std::make_pair(tag, new Json::Value(value))); - } - } - - UnserializeUidMap(ResourceType_Patient, serialized, MAP_PATIENTS); - UnserializeUidMap(ResourceType_Study, serialized, MAP_STUDIES); - UnserializeUidMap(ResourceType_Series, serialized, MAP_SERIES); - UnserializeUidMap(ResourceType_Instance, serialized, MAP_INSTANCES); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomModification.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,201 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ParsedDicomFile.h" - -namespace Orthanc -{ - class DicomModification : public boost::noncopyable - { - /** - * Process: - * (1) Remove private tags - * (2) Remove tags specified by the user - * (3) Replace tags - **/ - - public: - enum TagOperation - { - TagOperation_Keep, - TagOperation_Remove - }; - - class IDicomIdentifierGenerator : public boost::noncopyable - { - public: - virtual ~IDicomIdentifierGenerator() - { - } - - virtual bool Apply(std::string& target, - const std::string& sourceIdentifier, - ResourceType level, - const DicomMap& sourceDicom) = 0; - }; - - private: - class RelationshipsVisitor; - - typedef std::set SetOfTags; - typedef std::map Replacements; - typedef std::map< std::pair, std::string> UidMap; - - SetOfTags removals_; - SetOfTags clearings_; - Replacements replacements_; - bool removePrivateTags_; - ResourceType level_; - UidMap uidMap_; - SetOfTags privateTagsToKeep_; - bool allowManualIdentifiers_; - bool keepStudyInstanceUid_; - bool keepSeriesInstanceUid_; - bool keepSopInstanceUid_; - bool updateReferencedRelationships_; - bool isAnonymization_; - DicomMap currentSource_; - std::string privateCreator_; - - IDicomIdentifierGenerator* identifierGenerator_; - - std::string MapDicomIdentifier(const std::string& original, - ResourceType level); - - void RegisterMappedDicomIdentifier(const std::string& original, - const std::string& mapped, - ResourceType level); - - void MapDicomTags(ParsedDicomFile& dicom, - ResourceType level); - - void MarkNotOrthancAnonymization(); - - void ClearReplacements(); - - bool CancelReplacement(const DicomTag& tag); - - void ReplaceInternal(const DicomTag& tag, - const Json::Value& value); - - void SetupAnonymization2008(); - - void SetupAnonymization2017c(); - - void UnserializeUidMap(ResourceType level, - const Json::Value& serialized, - const char* field); - - public: - DicomModification(); - - DicomModification(const Json::Value& serialized); - - ~DicomModification(); - - void Keep(const DicomTag& tag); - - void Remove(const DicomTag& tag); - - // Replace the DICOM tag as a NULL/empty value (e.g. for anonymization) - void Clear(const DicomTag& tag); - - bool IsRemoved(const DicomTag& tag) const; - - bool IsCleared(const DicomTag& tag) const; - - // "safeForAnonymization" tells Orthanc that this replacement does - // not break the anonymization process it implements (for internal use only) - void Replace(const DicomTag& tag, - const Json::Value& value, // Encoded using UTF-8 - bool safeForAnonymization); - - bool IsReplaced(const DicomTag& tag) const; - - const Json::Value& GetReplacement(const DicomTag& tag) const; - - std::string GetReplacementAsString(const DicomTag& tag) const; - - void SetRemovePrivateTags(bool removed); - - bool ArePrivateTagsRemoved() const - { - return removePrivateTags_; - } - - void SetLevel(ResourceType level); - - ResourceType GetLevel() const - { - return level_; - } - - void SetupAnonymization(DicomVersion version); - - void Apply(ParsedDicomFile& toModify); - - void SetAllowManualIdentifiers(bool check) - { - allowManualIdentifiers_ = check; - } - - bool AreAllowManualIdentifiers() const - { - return allowManualIdentifiers_; - } - - void ParseModifyRequest(const Json::Value& request); - - void ParseAnonymizationRequest(bool& patientNameReplaced, - const Json::Value& request); - - void SetDicomIdentifierGenerator(IDicomIdentifierGenerator& generator) - { - identifierGenerator_ = &generator; - } - - void Serialize(Json::Value& value) const; - - void SetPrivateCreator(const std::string& privateCreator) - { - privateCreator_ = privateCreator; - } - - const std::string& GetPrivateCreator() - { - return privateCreator_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,673 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "DicomWebJsonVisitor.h" - -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "FromDcmtkBridge.h" - -#include -#include - - -static const char* const KEY_ALPHABETIC = "Alphabetic"; -static const char* const KEY_IDEOGRAPHIC = "Ideographic"; -static const char* const KEY_PHONETIC = "Phonetic"; -static const char* const KEY_BULK_DATA_URI = "BulkDataURI"; -static const char* const KEY_INLINE_BINARY = "InlineBinary"; -static const char* const KEY_SQ = "SQ"; -static const char* const KEY_TAG = "tag"; -static const char* const KEY_VALUE = "Value"; -static const char* const KEY_VR = "vr"; - - -namespace Orthanc -{ -#if ORTHANC_ENABLE_PUGIXML == 1 - static void DecomposeXmlPersonName(pugi::xml_node& target, - const std::string& source) - { - std::vector tokens; - Toolbox::TokenizeString(tokens, source, '^'); - - if (tokens.size() >= 1) - { - target.append_child("FamilyName").text() = tokens[0].c_str(); - } - - if (tokens.size() >= 2) - { - target.append_child("GivenName").text() = tokens[1].c_str(); - } - - if (tokens.size() >= 3) - { - target.append_child("MiddleName").text() = tokens[2].c_str(); - } - - if (tokens.size() >= 4) - { - target.append_child("NamePrefix").text() = tokens[3].c_str(); - } - - if (tokens.size() >= 5) - { - target.append_child("NameSuffix").text() = tokens[4].c_str(); - } - } - - static void ExploreXmlDataset(pugi::xml_node& target, - const Json::Value& source) - { - // http://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_F.3.html#table_F.3.1-1 - assert(source.type() == Json::objectValue); - - Json::Value::Members members = source.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const DicomTag tag = FromDcmtkBridge::ParseTag(members[i]); - const Json::Value& content = source[members[i]]; - - assert(content.type() == Json::objectValue && - content.isMember(KEY_VR) && - content[KEY_VR].type() == Json::stringValue); - const std::string vr = content[KEY_VR].asString(); - - const std::string keyword = FromDcmtkBridge::GetTagName(tag, ""); - - pugi::xml_node node = target.append_child("DicomAttribute"); - node.append_attribute(KEY_TAG).set_value(members[i].c_str()); - node.append_attribute(KEY_VR).set_value(vr.c_str()); - - if (keyword != std::string(DcmTag_ERROR_TagName)) - { - node.append_attribute("keyword").set_value(keyword.c_str()); - } - - if (content.isMember(KEY_VALUE)) - { - assert(content[KEY_VALUE].type() == Json::arrayValue); - - for (Json::Value::ArrayIndex j = 0; j < content[KEY_VALUE].size(); j++) - { - std::string number = boost::lexical_cast(j + 1); - - if (vr == "SQ") - { - if (content[KEY_VALUE][j].type() == Json::objectValue) - { - pugi::xml_node child = node.append_child("Item"); - child.append_attribute("number").set_value(number.c_str()); - ExploreXmlDataset(child, content[KEY_VALUE][j]); - } - } - if (vr == "PN") - { - bool hasAlphabetic = (content[KEY_VALUE][j].isMember(KEY_ALPHABETIC) && - content[KEY_VALUE][j][KEY_ALPHABETIC].type() == Json::stringValue); - - bool hasIdeographic = (content[KEY_VALUE][j].isMember(KEY_IDEOGRAPHIC) && - content[KEY_VALUE][j][KEY_IDEOGRAPHIC].type() == Json::stringValue); - - bool hasPhonetic = (content[KEY_VALUE][j].isMember(KEY_PHONETIC) && - content[KEY_VALUE][j][KEY_PHONETIC].type() == Json::stringValue); - - if (hasAlphabetic || - hasIdeographic || - hasPhonetic) - { - pugi::xml_node child = node.append_child("PersonName"); - child.append_attribute("number").set_value(number.c_str()); - - if (hasAlphabetic) - { - pugi::xml_node name = child.append_child(KEY_ALPHABETIC); - DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_ALPHABETIC].asString()); - } - - if (hasIdeographic) - { - pugi::xml_node name = child.append_child(KEY_IDEOGRAPHIC); - DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_IDEOGRAPHIC].asString()); - } - - if (hasPhonetic) - { - pugi::xml_node name = child.append_child(KEY_PHONETIC); - DecomposeXmlPersonName(name, content[KEY_VALUE][j][KEY_PHONETIC].asString()); - } - } - } - else - { - pugi::xml_node child = node.append_child("Value"); - child.append_attribute("number").set_value(number.c_str()); - - switch (content[KEY_VALUE][j].type()) - { - case Json::stringValue: - child.text() = content[KEY_VALUE][j].asCString(); - break; - - case Json::realValue: - child.text() = content[KEY_VALUE][j].asFloat(); - break; - - case Json::intValue: - child.text() = content[KEY_VALUE][j].asInt(); - break; - - case Json::uintValue: - child.text() = content[KEY_VALUE][j].asUInt(); - break; - - default: - break; - } - } - } - } - else if (content.isMember(KEY_BULK_DATA_URI) && - content[KEY_BULK_DATA_URI].type() == Json::stringValue) - { - pugi::xml_node child = node.append_child("BulkData"); - child.append_attribute("URI").set_value(content[KEY_BULK_DATA_URI].asCString()); - } - else if (content.isMember(KEY_INLINE_BINARY) && - content[KEY_INLINE_BINARY].type() == Json::stringValue) - { - pugi::xml_node child = node.append_child("InlineBinary"); - child.text() = content[KEY_INLINE_BINARY].asCString(); - } - } - } -#endif - - -#if ORTHANC_ENABLE_PUGIXML == 1 - static void DicomWebJsonToXml(pugi::xml_document& target, - const Json::Value& source) - { - pugi::xml_node root = target.append_child("NativeDicomModel"); - root.append_attribute("xmlns").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM"); - root.append_attribute("xsi:schemaLocation").set_value("http://dicom.nema.org/PS3.19/models/NativeDICOM"); - root.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance"); - - ExploreXmlDataset(root, source); - - pugi::xml_node decl = target.prepend_child(pugi::node_declaration); - decl.append_attribute("version").set_value("1.0"); - decl.append_attribute("encoding").set_value("utf-8"); - } -#endif - - - std::string DicomWebJsonVisitor::FormatTag(const DicomTag& tag) - { - char buf[16]; - sprintf(buf, "%04X%04X", tag.GetGroup(), tag.GetElement()); - return std::string(buf); - } - - - Json::Value& DicomWebJsonVisitor::CreateNode(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag) - { - assert(parentTags.size() == parentIndexes.size()); - - Json::Value* node = &result_; - - for (size_t i = 0; i < parentTags.size(); i++) - { - std::string t = FormatTag(parentTags[i]); - - if (!node->isMember(t)) - { - Json::Value item = Json::objectValue; - item[KEY_VR] = KEY_SQ; - item[KEY_VALUE] = Json::arrayValue; - item[KEY_VALUE].append(Json::objectValue); - (*node) [t] = item; - - node = &(*node)[t][KEY_VALUE][0]; - } - else if ((*node) [t].type() != Json::objectValue || - !(*node) [t].isMember(KEY_VR) || - (*node) [t][KEY_VR].type() != Json::stringValue || - (*node) [t][KEY_VR].asString() != KEY_SQ || - !(*node) [t].isMember(KEY_VALUE) || - (*node) [t][KEY_VALUE].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - size_t currentSize = (*node) [t][KEY_VALUE].size(); - - if (parentIndexes[i] < currentSize) - { - // The node already exists - } - else if (parentIndexes[i] == currentSize) - { - (*node) [t][KEY_VALUE].append(Json::objectValue); - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - - node = &(*node) [t][KEY_VALUE][Json::ArrayIndex(parentIndexes[i])]; - } - } - - assert(node->type() == Json::objectValue); - - std::string t = FormatTag(tag); - if (node->isMember(t)) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - (*node) [t] = Json::objectValue; - return (*node) [t]; - } - } - - - Json::Value DicomWebJsonVisitor::FormatInteger(int64_t value) - { - if (value < 0) - { - return Json::Value(static_cast(value)); - } - else - { - return Json::Value(static_cast(value)); - } - } - - - Json::Value DicomWebJsonVisitor::FormatDouble(double value) - { - try - { - long long a = boost::math::llround(value); - - double d = fabs(value - static_cast(a)); - - if (d <= std::numeric_limits::epsilon() * 100.0) - { - return FormatInteger(a); - } - else - { - return Json::Value(value); - } - } - catch (boost::math::rounding_error&) - { - // Can occur if "long long" is too small to receive this value - // (e.g. infinity) - return Json::Value(value); - } - } - - -#if ORTHANC_ENABLE_PUGIXML == 1 - void DicomWebJsonVisitor::FormatXml(std::string& target) const - { - pugi::xml_document doc; - DicomWebJsonToXml(doc, result_); - Toolbox::XmlToString(target, doc); - } -#endif - - - void DicomWebJsonVisitor::VisitEmptySequence(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag) - { - if (tag.GetElement() != 0x0000) - { - Json::Value& node = CreateNode(parentTags, parentIndexes, tag); - node[KEY_VR] = EnumerationToString(ValueRepresentation_Sequence); - } - } - - - void DicomWebJsonVisitor::VisitBinary(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const void* data, - size_t size) - { - assert(vr == ValueRepresentation_OtherByte || - vr == ValueRepresentation_OtherDouble || - vr == ValueRepresentation_OtherFloat || - vr == ValueRepresentation_OtherLong || - vr == ValueRepresentation_OtherWord || - vr == ValueRepresentation_Unknown); - - if (tag.GetElement() != 0x0000) - { - BinaryMode mode; - std::string bulkDataUri; - - if (formatter_ == NULL) - { - mode = BinaryMode_InlineBinary; - } - else - { - mode = formatter_->Format(bulkDataUri, parentTags, parentIndexes, tag, vr); - } - - if (mode != BinaryMode_Ignore) - { - Json::Value& node = CreateNode(parentTags, parentIndexes, tag); - node[KEY_VR] = EnumerationToString(vr); - - switch (mode) - { - case BinaryMode_BulkDataUri: - node[KEY_BULK_DATA_URI] = bulkDataUri; - break; - - case BinaryMode_InlineBinary: - { - std::string tmp(static_cast(data), size); - - std::string base64; - Toolbox::EncodeBase64(base64, tmp); - - node[KEY_INLINE_BINARY] = base64; - break; - } - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - } - } - - - void DicomWebJsonVisitor::VisitIntegers(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) - { - if (tag.GetElement() != 0x0000 && - vr != ValueRepresentation_NotSupported) - { - Json::Value& node = CreateNode(parentTags, parentIndexes, tag); - node[KEY_VR] = EnumerationToString(vr); - - if (!values.empty()) - { - Json::Value content = Json::arrayValue; - for (size_t i = 0; i < values.size(); i++) - { - content.append(FormatInteger(values[i])); - } - - node[KEY_VALUE] = content; - } - } - } - - void DicomWebJsonVisitor::VisitDoubles(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) - { - if (tag.GetElement() != 0x0000 && - vr != ValueRepresentation_NotSupported) - { - Json::Value& node = CreateNode(parentTags, parentIndexes, tag); - node[KEY_VR] = EnumerationToString(vr); - - if (!values.empty()) - { - Json::Value content = Json::arrayValue; - for (size_t i = 0; i < values.size(); i++) - { - content.append(FormatDouble(values[i])); - } - - node[KEY_VALUE] = content; - } - } - } - - - void DicomWebJsonVisitor::VisitAttributes(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - const std::vector& values) - { - if (tag.GetElement() != 0x0000) - { - Json::Value& node = CreateNode(parentTags, parentIndexes, tag); - node[KEY_VR] = EnumerationToString(ValueRepresentation_AttributeTag); - - if (!values.empty()) - { - Json::Value content = Json::arrayValue; - for (size_t i = 0; i < values.size(); i++) - { - content.append(FormatTag(values[i])); - } - - node[KEY_VALUE] = content; - } - } - } - - - ITagVisitor::Action - DicomWebJsonVisitor::VisitString(std::string& newValue, - const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::string& value) - { - if (tag.GetElement() == 0x0000 || - vr == ValueRepresentation_NotSupported) - { - return Action_None; - } - else - { - Json::Value& node = CreateNode(parentTags, parentIndexes, tag); - node[KEY_VR] = EnumerationToString(vr); - -#if 0 - /** - * TODO - The JSON file has an UTF-8 encoding, thus DCMTK - * replaces the specific character set with "ISO_IR 192" - * (UNICODE UTF-8). On Google Cloud Healthcare, however, the - * source encoding is reported, which seems more logical. We - * thus choose the Google convention. Enabling this block will - * mimic the DCMTK behavior. - **/ - if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - node[KEY_VALUE].append("ISO_IR 192"); - } - else -#endif - { - std::string truncated; - - if (!value.empty() && - value[value.size() - 1] == '\0') - { - truncated = value.substr(0, value.size() - 1); - } - else - { - truncated = value; - } - - if (!truncated.empty()) - { - std::vector tokens; - Toolbox::TokenizeString(tokens, truncated, '\\'); - - if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET && - tokens.size() > 1 && - tokens[0].empty()) - { - // Specific character set with code extension: Remove the - // first element from the vector of encodings - tokens.erase(tokens.begin()); - } - - node[KEY_VALUE] = Json::arrayValue; - for (size_t i = 0; i < tokens.size(); i++) - { - try - { - switch (vr) - { - case ValueRepresentation_PersonName: - { - Json::Value value = Json::objectValue; - if (!tokens[i].empty()) - { - std::vector components; - Toolbox::TokenizeString(components, tokens[i], '='); - - if (components.size() >= 1) - { - value[KEY_ALPHABETIC] = components[0]; - } - - if (components.size() >= 2) - { - value[KEY_IDEOGRAPHIC] = components[1]; - } - - if (components.size() >= 3) - { - value[KEY_PHONETIC] = components[2]; - } - } - - node[KEY_VALUE].append(value); - break; - } - - case ValueRepresentation_IntegerString: - { - /** - * The calls to "StripSpaces()" below fix the - * issue reported by Rana Asim Wajid on 2019-06-05 - * ("Error Exception while invoking plugin service - * 32: Bad file format"): - * https://groups.google.com/d/msg/orthanc-users/T32FovWPcCE/-hKFbfRJBgAJ - **/ - - std::string t = Orthanc::Toolbox::StripSpaces(tokens[i]); - if (t.empty()) - { - node[KEY_VALUE].append(Json::nullValue); - } - else - { - int64_t value = boost::lexical_cast(t); - node[KEY_VALUE].append(FormatInteger(value)); - } - - break; - } - - case ValueRepresentation_DecimalString: - { - std::string t = Orthanc::Toolbox::StripSpaces(tokens[i]); - if (t.empty()) - { - node[KEY_VALUE].append(Json::nullValue); - } - else - { - double value = boost::lexical_cast(t); - node[KEY_VALUE].append(FormatDouble(value)); - } - - break; - } - - default: - if (tokens[i].empty()) - { - node[KEY_VALUE].append(Json::nullValue); - } - else - { - node[KEY_VALUE].append(tokens[i]); - } - - break; - } - } - catch (boost::bad_lexical_cast&) - { - std::string tmp; - if (value.size() < 64 && - Toolbox::IsAsciiString(value)) - { - tmp = ": " + value; - } - - LOG(WARNING) << "Ignoring DICOM tag (" << tag.Format() - << ") with invalid content for VR " << EnumerationToString(vr) << tmp; - } - } - } - } - } - - return Action_None; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/DicomWebJsonVisitor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_PUGIXML) -# error Macro ORTHANC_ENABLE_PUGIXML must be defined to use this file -#endif - -#include "ITagVisitor.h" - -#include - - -namespace Orthanc -{ - class DicomWebJsonVisitor : public ITagVisitor - { - public: - enum BinaryMode - { - BinaryMode_Ignore, - BinaryMode_BulkDataUri, - BinaryMode_InlineBinary - }; - - class IBinaryFormatter : public boost::noncopyable - { - public: - virtual ~IBinaryFormatter() - { - } - - virtual BinaryMode Format(std::string& bulkDataUri, - const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr) = 0; - }; - - private: - Json::Value result_; - IBinaryFormatter *formatter_; - - static std::string FormatTag(const DicomTag& tag); - - Json::Value& CreateNode(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag); - - static Json::Value FormatInteger(int64_t value); - - static Json::Value FormatDouble(double value); - - public: - DicomWebJsonVisitor() : - formatter_(NULL) - { - Clear(); - } - - void SetFormatter(IBinaryFormatter& formatter) - { - formatter_ = &formatter; - } - - void Clear() - { - result_ = Json::objectValue; - } - - const Json::Value& GetResult() const - { - return result_; - } - -#if ORTHANC_ENABLE_PUGIXML == 1 - void FormatXml(std::string& target) const; -#endif - - virtual void VisitNotSupported(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr) - ORTHANC_OVERRIDE - { - } - - virtual void VisitEmptySequence(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag) - ORTHANC_OVERRIDE; - - virtual void VisitBinary(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const void* data, - size_t size) - ORTHANC_OVERRIDE; - - virtual void VisitIntegers(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) - ORTHANC_OVERRIDE; - - virtual void VisitDoubles(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) - ORTHANC_OVERRIDE; - - virtual void VisitAttributes(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - const std::vector& values) - ORTHANC_OVERRIDE; - - virtual Action VisitString(std::string& newValue, - const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::string& value) - ORTHANC_OVERRIDE; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2668 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if !defined(DCMTK_VERSION_NUMBER) -# error The macro DCMTK_VERSION_NUMBER must be defined -#endif - -#include "FromDcmtkBridge.h" -#include "ToDcmtkBridge.h" -#include "../Compatibility.h" -#include "../Logging.h" -#include "../Toolbox.h" -#include "../OrthancException.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../TemporaryFile.h" -#endif - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if DCMTK_VERSION_NUMBER >= 361 -# include -# include -#endif - -#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 -# include -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 -# include -# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 -# include -# endif -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 -# include -# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 -# include -# endif -#endif - - -#include -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 -# include -# include // include to support color images -#endif - - -namespace Orthanc -{ - static bool IsBinaryTag(const DcmTag& key) - { - return (key.isUnknownVR() || - key.getEVR() == EVR_OB || - key.getEVR() == EVR_OW || - key.getEVR() == EVR_UN || - key.getEVR() == EVR_ox); - } - - -#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 - static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary, - EmbeddedResources::FileResourceId resource) - { - std::string content; - EmbeddedResources::GetFileResource(content, resource); - -#if ORTHANC_SANDBOXED == 0 - TemporaryFile tmp; - tmp.Write(content); - - if (!dictionary.loadDictionary(tmp.GetPath().c_str())) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot read embedded dictionary. Under Windows, make sure that " - "your TEMP directory does not contain special characters."); - } -#else - if (!dictionary.loadFromMemory(content)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot read embedded dictionary. Under Windows, make sure that " - "your TEMP directory does not contain special characters."); - } -#endif - } -#endif - - - namespace - { - class DictionaryLocker - { - private: - DcmDataDictionary& dictionary_; - - public: - DictionaryLocker() : dictionary_(dcmDataDict.wrlock()) - { - } - - ~DictionaryLocker() - { -#if DCMTK_VERSION_NUMBER >= 364 - dcmDataDict.wrunlock(); -#else - dcmDataDict.unlock(); -#endif - } - - DcmDataDictionary& operator*() - { - return dictionary_; - } - - DcmDataDictionary* operator->() - { - return &dictionary_; - } - }; - - -#define DCMTK_TO_CTYPE_CONVERTER(converter, cType, dcmtkType, getter) \ - \ - struct converter \ - { \ - typedef cType CType; \ - \ - static bool Apply(CType& result, \ - DcmElement& element, \ - size_t i) \ - { \ - return dynamic_cast(element).getter(result, i).good(); \ - } \ - }; - -DCMTK_TO_CTYPE_CONVERTER(DcmtkToSint32Converter, Sint32, DcmSignedLong, getSint32) -DCMTK_TO_CTYPE_CONVERTER(DcmtkToSint16Converter, Sint16, DcmSignedShort, getSint16) -DCMTK_TO_CTYPE_CONVERTER(DcmtkToUint32Converter, Uint32, DcmUnsignedLong, getUint32) -DCMTK_TO_CTYPE_CONVERTER(DcmtkToUint16Converter, Uint16, DcmUnsignedShort, getUint16) -DCMTK_TO_CTYPE_CONVERTER(DcmtkToFloat32Converter, Float32, DcmFloatingPointSingle, getFloat32) -DCMTK_TO_CTYPE_CONVERTER(DcmtkToFloat64Converter, Float64, DcmFloatingPointDouble, getFloat64) - - - template - static DicomValue* ApplyDcmtkToCTypeConverter(DcmElement& element) - { - F f; - typename F::CType value; - - if (element.getLength() > sizeof(typename F::CType) - && (element.getLength() % sizeof(typename F::CType)) == 0) - { - size_t count = element.getLength() / sizeof(typename F::CType); - std::vector strings; - for (size_t i = 0; i < count; i++) { - if (f.Apply(value, element, i)) { - strings.push_back(boost::lexical_cast(value)); - } - } - return new DicomValue(boost::algorithm::join(strings, "\\"), false); - } - else if (f.Apply(value, element, 0)) { - return new DicomValue(boost::lexical_cast(value), false); - } - else { - return new DicomValue; - } - } - - } - - - void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary) - { - LOG(INFO) << "Using DCTMK version: " << DCMTK_VERSION_NUMBER; - - { - DictionaryLocker locker; - - locker->clear(); - -#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 - LOG(INFO) << "Loading the embedded dictionaries"; - /** - * Do not load DICONDE dictionary, it breaks the other tags. The - * command "strace storescu 2>&1 |grep dic" shows that DICONDE - * dictionary is not loaded by storescu. - **/ - //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE); - - LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM); - - if (loadPrivateDictionary) - { - LOG(INFO) << "Loading the embedded dictionary of private tags"; - LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE); - } - else - { - LOG(INFO) << "The dictionary of private tags has not been loaded"; - } - -#else - std::vector dictionaries; - - const char* env = std::getenv(DCM_DICT_ENVIRONMENT_VARIABLE); - if (env != NULL) - { - // This mimics the behavior of DCMTK: - // https://support.dcmtk.org/docs/file_envvars.html -#if defined(_WIN32) - Toolbox::TokenizeString(dictionaries, std::string(env), ';'); -#else - Toolbox::TokenizeString(dictionaries, std::string(env), ':'); -#endif - } - else - { - boost::filesystem::path base = DCMTK_DICTIONARY_DIR; - dictionaries.push_back((base / "dicom.dic").string()); - dictionaries.push_back((base / "private.dic").string()); - } - - for (size_t i = 0; i < dictionaries.size(); i++) - { - LOG(WARNING) << "Loading external DICOM dictionary: \"" << dictionaries[i] << "\""; - - if (!locker->loadDictionary(dictionaries[i].c_str())) - { - throw OrthancException(ErrorCode_InexistentFile); - } - } - -#endif - } - - /* make sure data dictionary is loaded */ - if (!dcmDataDict.isDictionaryLoaded()) - { - throw OrthancException(ErrorCode_InternalError, - "No DICOM dictionary loaded, check environment variable: " + - std::string(DCM_DICT_ENVIRONMENT_VARIABLE)); - } - - { - // Test the dictionary with a simple DICOM tag - DcmTag key(0x0010, 0x1030); // This is PatientWeight - if (key.getEVR() != EVR_DS) - { - throw OrthancException(ErrorCode_InternalError, - "The DICOM dictionary has not been correctly read"); - } - } - } - - - void FromDcmtkBridge::RegisterDictionaryTag(const DicomTag& tag, - ValueRepresentation vr, - const std::string& name, - unsigned int minMultiplicity, - unsigned int maxMultiplicity, - const std::string& privateCreator) - { - if (minMultiplicity < 1) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - bool arbitrary = false; - if (maxMultiplicity == 0) - { - maxMultiplicity = DcmVariableVM; - arbitrary = true; - } - else if (maxMultiplicity < minMultiplicity) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - DcmEVR evr = ToDcmtkBridge::Convert(vr); - - LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(evr).getValidVRName()) << " " - << name << " (multiplicity: " << minMultiplicity << "-" - << (arbitrary ? "n" : boost::lexical_cast(maxMultiplicity)) << ")"; - - std::unique_ptr entry; - if (privateCreator.empty()) - { - if (tag.GetGroup() % 2 == 1) - { - char buf[128]; - sprintf(buf, "Warning: You are registering a private tag (%04x,%04x), " - "but no private creator was associated with it", - tag.GetGroup(), tag.GetElement()); - LOG(WARNING) << buf; - } - - entry.reset(new DcmDictEntry(tag.GetGroup(), - tag.GetElement(), - evr, name.c_str(), - static_cast(minMultiplicity), - static_cast(maxMultiplicity), - NULL /* version */, - OFTrue /* doCopyString */, - NULL /* private creator */)); - } - else - { - // "Private Data Elements have an odd Group Number that is not - // (0001,eeee), (0003,eeee), (0005,eeee), (0007,eeee), or - // (FFFF,eeee)." - if (tag.GetGroup() % 2 == 0 /* even */ || - tag.GetGroup() == 0x0001 || - tag.GetGroup() == 0x0003 || - tag.GetGroup() == 0x0005 || - tag.GetGroup() == 0x0007 || - tag.GetGroup() == 0xffff) - { - char buf[128]; - sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009", - tag.GetGroup(), tag.GetElement()); - throw OrthancException(ErrorCode_ParameterOutOfRange, std::string(buf)); - } - - entry.reset(new DcmDictEntry(tag.GetGroup(), - tag.GetElement(), - evr, name.c_str(), - static_cast(minMultiplicity), - static_cast(maxMultiplicity), - "private" /* version */, - OFTrue /* doCopyString */, - privateCreator.c_str())); - } - - entry->setGroupRangeRestriction(DcmDictRange_Unspecified); - entry->setElementRangeRestriction(DcmDictRange_Unspecified); - - { - DictionaryLocker locker; - - if (locker->findEntry(name.c_str())) - { - throw OrthancException(ErrorCode_AlreadyExistingTag, - "Cannot register two tags with the same symbolic name \"" + name + "\""); - } - - locker->addEntry(entry.release()); - } - } - - - Encoding FromDcmtkBridge::DetectEncoding(bool& hasCodeExtensions, - DcmItem& dataset, - Encoding defaultEncoding) - { - // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.12.html#sect_C.12.1.1.2 - - OFString tmp; - if (dataset.findAndGetOFStringArray(DCM_SpecificCharacterSet, tmp).good()) - { - std::vector tokens; - Toolbox::TokenizeString(tokens, std::string(tmp.c_str()), '\\'); - - hasCodeExtensions = (tokens.size() > 1); - - for (size_t i = 0; i < tokens.size(); i++) - { - std::string characterSet = Toolbox::StripSpaces(tokens[i]); - - if (!characterSet.empty()) - { - Encoding encoding; - - if (GetDicomEncoding(encoding, characterSet.c_str())) - { - // The specific character set is supported by the Orthanc core - return encoding; - } - else - { - LOG(WARNING) << "Value of Specific Character Set (0008,0005) is not supported: " << characterSet - << ", fallback to ASCII (remove all special characters)"; - return Encoding_Ascii; - } - } - } - } - else - { - hasCodeExtensions = false; - } - - // No specific character set tag: Use the default encoding - return defaultEncoding; - } - - - void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, - DcmItem& dataset, - unsigned int maxStringLength, - Encoding defaultEncoding, - const std::set& ignoreTagLength) - { - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); - - target.Clear(); - for (unsigned long i = 0; i < dataset.card(); i++) - { - DcmElement* element = dataset.getElement(i); - if (element && element->isLeaf()) - { - target.SetValueInternal(element->getTag().getGTag(), - element->getTag().getETag(), - ConvertLeafElement(*element, DicomToJsonFlags_Default, - maxStringLength, encoding, hasCodeExtensions, ignoreTagLength)); - } - } - } - - - DicomTag FromDcmtkBridge::Convert(const DcmTag& tag) - { - return DicomTag(tag.getGTag(), tag.getETag()); - } - - - DicomTag FromDcmtkBridge::GetTag(const DcmElement& element) - { - return DicomTag(element.getGTag(), element.getETag()); - } - - - DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding, - bool hasCodeExtensions, - const std::set& ignoreTagLength) - { - if (!element.isLeaf()) - { - // This function is only applicable to leaf elements - throw OrthancException(ErrorCode_BadParameterType); - } - - char *c = NULL; - if (element.isaString() && - element.getString(c).good()) - { - if (c == NULL) // This case corresponds to the empty string - { - return new DicomValue("", false); - } - else - { - std::string s(c); - std::string utf8 = Toolbox::ConvertToUtf8(s, encoding, hasCodeExtensions); - - if (maxStringLength != 0 && - utf8.size() > maxStringLength && - ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end()) - { - return new DicomValue; // Too long, create a NULL value - } - else - { - return new DicomValue(utf8, false); - } - } - } - - - if (element.getVR() == EVR_UN) - { - // Unknown value representation: Lookup in the dictionary. This - // is notably the case for private tags registered with the - // "Dictionary" configuration option. - DictionaryLocker locker; - - const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(), - element.getTag().getPrivateCreator()); - if (entry != NULL && - entry->getVR().isaString()) - { - Uint8* data = NULL; - - // At (*), we do not try and convert to UTF-8, as nothing says - // the encoding of the private tag is the same as that of the - // remaining of the DICOM dataset. Only go for ASCII strings. - - if (element.getUint8Array(data) == EC_Normal && - Toolbox::IsAsciiString(data, element.getLength())) // (*) - { - if (data == NULL) - { - return new DicomValue("", false); // Empty string - } - else if (maxStringLength != 0 && - element.getLength() > maxStringLength && - ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end()) - { - return new DicomValue; // Too long, create a NULL value - } - else - { - std::string s(reinterpret_cast(data), element.getLength()); - return new DicomValue(s, false); - } - } - } - } - - - try - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - switch (element.getVR()) - { - - /** - * Deal with binary data (including PixelData). - **/ - - case EVR_OB: // other byte - case EVR_OF: // other float - case EVR_OW: // other word - case EVR_UN: // unknown value representation - case EVR_ox: // OB or OW depending on context - case EVR_DS: // decimal string - case EVR_IS: // integer string - case EVR_AS: // age string - case EVR_DA: // date string - case EVR_DT: // date time string - case EVR_TM: // time string - case EVR_AE: // application entity title - case EVR_CS: // code string - case EVR_SH: // short string - case EVR_LO: // long string - case EVR_ST: // short text - case EVR_LT: // long text - case EVR_UT: // unlimited text - case EVR_PN: // person name - case EVR_UI: // unique identifier - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - { - if (!(flags & DicomToJsonFlags_ConvertBinaryToNull)) - { - Uint8* data = NULL; - if (element.getUint8Array(data) == EC_Normal) - { - return new DicomValue(reinterpret_cast(data), element.getLength(), true); - } - } - - return new DicomValue; - } - - /** - * Numeric types - **/ - - case EVR_SL: // signed long - { - return ApplyDcmtkToCTypeConverter(element); - } - - case EVR_SS: // signed short - { - return ApplyDcmtkToCTypeConverter(element); - } - - case EVR_UL: // unsigned long - { - return ApplyDcmtkToCTypeConverter(element); - } - - case EVR_US: // unsigned short - { - return ApplyDcmtkToCTypeConverter(element); - } - - case EVR_FL: // float single-precision - { - return ApplyDcmtkToCTypeConverter(element); - } - - case EVR_FD: // float double-precision - { - return ApplyDcmtkToCTypeConverter(element); - } - - - /** - * Attribute tag. - **/ - - case EVR_AT: - { - DcmTagKey tag; - if (dynamic_cast(element).getTagVal(tag, 0).good()) - { - DicomTag t(tag.getGroup(), tag.getElement()); - return new DicomValue(t.Format(), false); - } - else - { - return new DicomValue; - } - } - - - /** - * Sequence types, should never occur at this point because of - * "element.isLeaf()". - **/ - - case EVR_SQ: // sequence of items - return new DicomValue; - - - /** - * Internal to DCMTK. - **/ - - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - return new DicomValue; - - - /** - * Default case. - **/ - - default: - return new DicomValue; - } - } - catch (boost::bad_lexical_cast&) - { - return new DicomValue; - } - catch (std::bad_cast&) - { - return new DicomValue; - } - } - - - static Json::Value& PrepareNode(Json::Value& parent, - DcmElement& element, - DicomToJsonFormat format) - { - assert(parent.type() == Json::objectValue); - - DicomTag tag(FromDcmtkBridge::GetTag(element)); - const std::string formattedTag = tag.Format(); - - if (format == DicomToJsonFormat_Short) - { - parent[formattedTag] = Json::nullValue; - return parent[formattedTag]; - } - - // This code gives access to the name of the private tags - std::string tagName = FromDcmtkBridge::GetTagName(element); - - switch (format) - { - case DicomToJsonFormat_Human: - parent[tagName] = Json::nullValue; - return parent[tagName]; - - case DicomToJsonFormat_Full: - { - parent[formattedTag] = Json::objectValue; - Json::Value& node = parent[formattedTag]; - - if (element.isLeaf()) - { - node["Name"] = tagName; - - if (element.getTag().getPrivateCreator() != NULL) - { - node["PrivateCreator"] = element.getTag().getPrivateCreator(); - } - - return node; - } - else - { - node["Name"] = tagName; - node["Type"] = "Sequence"; - node["Value"] = Json::nullValue; - return node["Value"]; - } - } - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - static void LeafValueToJson(Json::Value& target, - const DicomValue& value, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength) - { - Json::Value* targetValue = NULL; - Json::Value* targetType = NULL; - - switch (format) - { - case DicomToJsonFormat_Short: - case DicomToJsonFormat_Human: - { - assert(target.type() == Json::nullValue); - targetValue = ⌖ - break; - } - - case DicomToJsonFormat_Full: - { - assert(target.type() == Json::objectValue); - target["Value"] = Json::nullValue; - target["Type"] = Json::nullValue; - targetType = &target["Type"]; - targetValue = &target["Value"]; - break; - } - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - assert(targetValue != NULL); - assert(targetValue->type() == Json::nullValue); - assert(targetType == NULL || targetType->type() == Json::nullValue); - - if (value.IsNull()) - { - if (targetType != NULL) - { - *targetType = "Null"; - } - } - else if (value.IsBinary()) - { - if (flags & DicomToJsonFlags_ConvertBinaryToAscii) - { - *targetValue = Toolbox::ConvertToAscii(value.GetContent()); - } - else - { - std::string s; - value.FormatDataUriScheme(s); - *targetValue = s; - } - - if (targetType != NULL) - { - *targetType = "Binary"; - } - } - else if (maxStringLength == 0 || - value.GetContent().size() <= maxStringLength) - { - *targetValue = value.GetContent(); - - if (targetType != NULL) - { - *targetType = "String"; - } - } - else - { - if (targetType != NULL) - { - *targetType = "TooLong"; - } - } - } - - - void FromDcmtkBridge::ElementToJson(Json::Value& parent, - DcmElement& element, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding, - bool hasCodeExtensions, - const std::set& ignoreTagLength) - { - if (parent.type() == Json::nullValue) - { - parent = Json::objectValue; - } - - assert(parent.type() == Json::objectValue); - Json::Value& target = PrepareNode(parent, element, format); - - if (element.isLeaf()) - { - // The "0" below lets "LeafValueToJson()" take care of "TooLong" values - std::unique_ptr v(FromDcmtkBridge::ConvertLeafElement - (element, flags, 0, encoding, hasCodeExtensions, ignoreTagLength)); - - if (ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end()) - { - LeafValueToJson(target, *v, format, flags, maxStringLength); - } - else - { - LeafValueToJson(target, *v, format, flags, 0); - } - } - else - { - assert(target.type() == Json::nullValue); - target = Json::arrayValue; - - // "All subclasses of DcmElement except for DcmSequenceOfItems - // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset - // etc. are not." The following dynamic_cast is thus OK. - DcmSequenceOfItems& sequence = dynamic_cast(element); - - for (unsigned long i = 0; i < sequence.card(); i++) - { - DcmItem* child = sequence.getItem(i); - Json::Value& v = target.append(Json::objectValue); - DatasetToJson(v, *child, format, flags, maxStringLength, encoding, hasCodeExtensions, ignoreTagLength); - } - } - } - - - void FromDcmtkBridge::DatasetToJson(Json::Value& parent, - DcmItem& item, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding, - bool hasCodeExtensions, - const std::set& ignoreTagLength) - { - assert(parent.type() == Json::objectValue); - - for (unsigned long i = 0; i < item.card(); i++) - { - DcmElement* element = item.getElement(i); - if (element == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); - - /*element->getTag().isPrivate()*/ - if (tag.IsPrivate() && - !(flags & DicomToJsonFlags_IncludePrivateTags)) - { - continue; - } - - if (!(flags & DicomToJsonFlags_IncludeUnknownTags)) - { - DictionaryLocker locker; - if (locker->findEntry(element->getTag(), element->getTag().getPrivateCreator()) == NULL) - { - continue; - } - } - - if (IsBinaryTag(element->getTag())) - { - // This is a binary tag - if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) || - (tag != DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludeBinary))) - { - continue; - } - } - - FromDcmtkBridge::ElementToJson(parent, *element, format, flags, - maxStringLength, encoding, hasCodeExtensions, ignoreTagLength); - } - } - - - void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, - DcmDataset& dataset, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding defaultEncoding, - const std::set& ignoreTagLength) - { - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); - - target = Json::objectValue; - DatasetToJson(target, dataset, format, flags, maxStringLength, encoding, hasCodeExtensions, ignoreTagLength); - } - - - void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target, - DcmMetaInfo& dataset, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength) - { - std::set ignoreTagLength; - target = Json::objectValue; - DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii, false, ignoreTagLength); - } - - - - static std::string GetTagNameInternal(DcmTag& tag) - { - { - // Some patches for important tags because of different DICOM - // dictionaries between DCMTK versions - DicomTag tmp(tag.getGroup(), tag.getElement()); - std::string n = tmp.GetMainTagsName(); - if (n.size() != 0) - { - return n; - } - // End of patches - } - -#if 0 - // This version explicitly calls the dictionary - const DcmDataDictionary& dict = dcmDataDict.rdlock(); - const DcmDictEntry* entry = dict.findEntry(tag, NULL); - - std::string s(DcmTag_ERROR_TagName); - if (entry != NULL) - { - s = std::string(entry->getTagName()); - } - - dcmDataDict.unlock(); - return s; -#else - const char* name = tag.getTagName(); - if (name == NULL) - { - return DcmTag_ERROR_TagName; - } - else - { - return std::string(name); - } -#endif - } - - - std::string FromDcmtkBridge::GetTagName(const DicomTag& t, - const std::string& privateCreator) - { - DcmTag tag(t.GetGroup(), t.GetElement()); - - if (!privateCreator.empty()) - { - tag.setPrivateCreator(privateCreator.c_str()); - } - - return GetTagNameInternal(tag); - } - - - std::string FromDcmtkBridge::GetTagName(const DcmElement& element) - { - // Copy the tag to ensure const-correctness of DcmElement. Note - // that the private creator information is also copied. - DcmTag tag(element.getTag()); - - return GetTagNameInternal(tag); - } - - - - DicomTag FromDcmtkBridge::ParseTag(const char* name) - { - DicomTag parsed(0, 0); - if (DicomTag::ParseHexadecimal(parsed, name)) - { - return parsed; - } - -#if 0 - const DcmDataDictionary& dict = dcmDataDict.rdlock(); - const DcmDictEntry* entry = dict.findEntry(name); - - if (entry == NULL) - { - dcmDataDict.unlock(); - throw OrthancException(ErrorCode_UnknownDicomTag); - } - else - { - DcmTagKey key = entry->getKey(); - DicomTag tag(key.getGroup(), key.getElement()); - dcmDataDict.unlock(); - return tag; - } -#else - DcmTag tag; - if (DcmTag::findTagFromName(name, tag).good()) - { - return DicomTag(tag.getGTag(), tag.getETag()); - } - else - { - LOG(INFO) << "Unknown DICOM tag: \"" << name << "\""; - throw OrthancException(ErrorCode_UnknownDicomTag); - } -#endif - } - - - bool FromDcmtkBridge::IsUnknownTag(const DicomTag& tag) - { - DcmTag tmp(tag.GetGroup(), tag.GetElement()); - return tmp.isUnknownVR(); - } - - - void FromDcmtkBridge::ToJson(Json::Value& result, - const DicomMap& values, - bool simplify) - { - if (result.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - result.clear(); - - for (DicomMap::Content::const_iterator - it = values.content_.begin(); it != values.content_.end(); ++it) - { - // TODO Inject PrivateCreator if some is available in the DicomMap? - const std::string tagName = GetTagName(it->first, ""); - - if (simplify) - { - if (it->second->IsNull()) - { - result[tagName] = Json::nullValue; - } - else - { - // TODO IsBinary - result[tagName] = it->second->GetContent(); - } - } - else - { - Json::Value value = Json::objectValue; - - value["Name"] = tagName; - - if (it->second->IsNull()) - { - value["Type"] = "Null"; - value["Value"] = Json::nullValue; - } - else - { - // TODO IsBinary - value["Type"] = "String"; - value["Value"] = it->second->GetContent(); - } - - result[it->first.Format()] = value; - } - } - } - - - std::string FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType level) - { - char uid[100]; - - switch (level) - { - case ResourceType_Patient: - // The "PatientID" field is of type LO (Long String), 64 - // Bytes Maximum. An UUID is of length 36, thus it can be used - // as a random PatientID. - return Toolbox::GenerateUuid(); - - case ResourceType_Instance: - return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT); - - case ResourceType_Series: - return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT); - - case ResourceType_Study: - return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT); - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - - static bool SaveToMemoryBufferInternal(std::string& buffer, - DcmFileFormat& dicom, - E_TransferSyntax xfer) - { - E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; - - // Create a memory buffer with the proper size - { - const uint32_t estimatedSize = dicom.calcElementLength(xfer, encodingType); // (*) - buffer.resize(estimatedSize); - } - - DcmOutputBufferStream ob(&buffer[0], buffer.size()); - - // Fill the memory buffer with the meta-header and the dataset - dicom.transferInit(); - OFCondition c = dicom.write(ob, xfer, encodingType, NULL, - /*opt_groupLength*/ EGL_recalcGL, - /*opt_paddingType*/ EPD_noChange, - /*padlen*/ 0, /*subPadlen*/ 0, /*instanceLength*/ 0, - EWM_updateMeta /* creates new SOP instance UID on lossy */); - dicom.transferEnd(); - - if (c.good()) - { - // The DICOM file is successfully written, truncate the target - // buffer if its size was overestimated by (*) - ob.flush(); - - size_t effectiveSize = static_cast(ob.tell()); - if (effectiveSize < buffer.size()) - { - buffer.resize(effectiveSize); - } - - return true; - } - else - { - // Error - buffer.clear(); - return false; - } - } - - - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, - DcmDataset& dataSet) - { - // Determine the transfer syntax which shall be used to write the - // information to the file. If not possible, switch to the Little - // Endian syntax, with explicit length. - - // http://support.dcmtk.org/docs/dcxfer_8h-source.html - - - /** - * Note that up to Orthanc 0.7.1 (inclusive), the - * "EXS_LittleEndianExplicit" was always used to save the DICOM - * dataset into memory. We now keep the original transfer syntax - * (if available). - **/ - E_TransferSyntax xfer = dataSet.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - // No information about the original transfer syntax: This is - // most probably a DICOM dataset that was read from memory. - xfer = EXS_LittleEndianExplicit; - } - - // Create the meta-header information - DcmFileFormat ff(&dataSet); - ff.validateMetaInfo(xfer); - ff.removeInvalidGroups(); - - return SaveToMemoryBufferInternal(buffer, ff, xfer); - } - - - bool FromDcmtkBridge::Transcode(DcmFileFormat& dicom, - DicomTransferSyntax syntax, - const DcmRepresentationParameter* representation) - { - E_TransferSyntax xfer; - if (!LookupDcmtkTransferSyntax(xfer, syntax)) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - DicomTransferSyntax sourceSyntax; - bool known = LookupOrthancTransferSyntax(sourceSyntax, dicom); - - if (!dicom.chooseRepresentation(xfer, representation).good() || - !dicom.canWriteXfer(xfer) || - !dicom.validateMetaInfo(xfer, EWM_updateMeta).good()) - { - return false; - } - else - { - dicom.removeInvalidGroups(); - - if (known) - { - LOG(INFO) << "Transcoded an image from transfer syntax " - << GetTransferSyntaxUid(sourceSyntax) << " to " - << GetTransferSyntaxUid(syntax); - } - else - { - LOG(INFO) << "Transcoded an image from unknown transfer syntax to " - << GetTransferSyntaxUid(syntax); - } - - return true; - } - } - } - - - ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag) - { - DcmTag t(tag.GetGroup(), tag.GetElement()); - return Convert(t.getEVR()); - } - - ValueRepresentation FromDcmtkBridge::Convert(const DcmEVR vr) - { - switch (vr) - { - case EVR_AE: - return ValueRepresentation_ApplicationEntity; - - case EVR_AS: - return ValueRepresentation_AgeString; - - case EVR_AT: - return ValueRepresentation_AttributeTag; - - case EVR_CS: - return ValueRepresentation_CodeString; - - case EVR_DA: - return ValueRepresentation_Date; - - case EVR_DS: - return ValueRepresentation_DecimalString; - - case EVR_DT: - return ValueRepresentation_DateTime; - - case EVR_FL: - return ValueRepresentation_FloatingPointSingle; - - case EVR_FD: - return ValueRepresentation_FloatingPointDouble; - - case EVR_IS: - return ValueRepresentation_IntegerString; - - case EVR_LO: - return ValueRepresentation_LongString; - - case EVR_LT: - return ValueRepresentation_LongText; - - case EVR_OB: - return ValueRepresentation_OtherByte; - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_OD: - return ValueRepresentation_OtherDouble; -#endif - - case EVR_OF: - return ValueRepresentation_OtherFloat; - -#if DCMTK_VERSION_NUMBER >= 362 - case EVR_OL: - return ValueRepresentation_OtherLong; -#endif - - case EVR_OW: - return ValueRepresentation_OtherWord; - - case EVR_PN: - return ValueRepresentation_PersonName; - - case EVR_SH: - return ValueRepresentation_ShortString; - - case EVR_SL: - return ValueRepresentation_SignedLong; - - case EVR_SQ: - return ValueRepresentation_Sequence; - - case EVR_SS: - return ValueRepresentation_SignedShort; - - case EVR_ST: - return ValueRepresentation_ShortText; - - case EVR_TM: - return ValueRepresentation_Time; - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UC: - return ValueRepresentation_UnlimitedCharacters; -#endif - - case EVR_UI: - return ValueRepresentation_UniqueIdentifier; - - case EVR_UL: - return ValueRepresentation_UnsignedLong; - - case EVR_UN: - return ValueRepresentation_Unknown; - -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UR: - return ValueRepresentation_UniversalResource; -#endif - - case EVR_US: - return ValueRepresentation_UnsignedShort; - - case EVR_UT: - return ValueRepresentation_UnlimitedText; - - default: - return ValueRepresentation_NotSupported; - } - } - - - DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag, - const std::string& privateCreator) - { - if (tag.IsPrivate() && - privateCreator.empty()) - { - // This solves issue 140 (Modifying private tags with REST API - // changes VR from LO to UN) - // https://bitbucket.org/sjodogne/orthanc/issues/140 - LOG(WARNING) << "Private creator should not be empty while creating a private tag: " << tag.Format(); - } - -#if DCMTK_VERSION_NUMBER >= 362 - DcmTag key(tag.GetGroup(), tag.GetElement()); - if (tag.IsPrivate()) - { - return DcmItem::newDicomElement(key, privateCreator.c_str()); - } - else - { - return DcmItem::newDicomElement(key, NULL); - } - -#else - DcmTag key(tag.GetGroup(), tag.GetElement()); - if (tag.IsPrivate()) - { - // https://forum.dcmtk.org/viewtopic.php?t=4527 - LOG(WARNING) << "You are using DCMTK <= 3.6.1: All the private tags " - "are considered as having a binary value representation"; - key.setPrivateCreator(privateCreator.c_str()); - return new DcmOtherByteOtherWord(key); - } - else - { - return newDicomElement(key); - } -#endif - } - - - - void FromDcmtkBridge::FillElementWithString(DcmElement& element, - const std::string& utf8Value, - bool decodeDataUriScheme, - Encoding dicomEncoding) - { - std::string binary; - const std::string* decoded = &utf8Value; - - if (decodeDataUriScheme && - boost::starts_with(utf8Value, URI_SCHEME_PREFIX_BINARY)) - { - std::string mime; - if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - decoded = &binary; - } - else if (dicomEncoding != Encoding_Utf8) - { - binary = Toolbox::ConvertFromUtf8(utf8Value, dicomEncoding); - decoded = &binary; - } - - if (IsBinaryTag(element.getTag())) - { - bool ok; - - switch (element.getTag().getEVR()) - { - case EVR_OW: - if (decoded->size() % sizeof(Uint16) != 0) - { - LOG(ERROR) << "A tag with OW VR must have an even number of bytes"; - ok = false; - } - else - { - ok = element.putUint16Array((const Uint16*) decoded->c_str(), decoded->size() / sizeof(Uint16)).good(); - } - - break; - - default: - ok = element.putUint8Array((const Uint8*) decoded->c_str(), decoded->size()).good(); - break; - } - - if (ok) - { - return; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - - bool ok = false; - - try - { - switch (element.getTag().getEVR()) - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - - /** - * TODO. - **/ - - case EVR_OB: // other byte - case EVR_OW: // other word - case EVR_AT: // attribute tag - throw OrthancException(ErrorCode_NotImplemented); - - case EVR_UN: // unknown value representation - throw OrthancException(ErrorCode_ParameterOutOfRange); - - - /** - * String types. - **/ - - case EVR_DS: // decimal string - case EVR_IS: // integer string - case EVR_AS: // age string - case EVR_DA: // date string - case EVR_DT: // date time string - case EVR_TM: // time string - case EVR_AE: // application entity title - case EVR_CS: // code string - case EVR_SH: // short string - case EVR_LO: // long string - case EVR_ST: // short text - case EVR_LT: // long text - case EVR_UT: // unlimited text - case EVR_PN: // person name - case EVR_UI: // unique identifier -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_UC: // unlimited characters - case EVR_UR: // URI/URL -#endif - { - ok = element.putString(decoded->c_str()).good(); - break; - } - - - /** - * Numerical types - **/ - - case EVR_SL: // signed long - { - ok = element.putSint32(boost::lexical_cast(*decoded)).good(); - break; - } - - case EVR_SS: // signed short - { - ok = element.putSint16(boost::lexical_cast(*decoded)).good(); - break; - } - - case EVR_UL: // unsigned long -#if DCMTK_VERSION_NUMBER >= 362 - case EVR_OL: // other long (requires byte-swapping) -#endif - { - ok = element.putUint32(boost::lexical_cast(*decoded)).good(); - break; - } - - case EVR_US: // unsigned short - { - ok = element.putUint16(boost::lexical_cast(*decoded)).good(); - break; - } - - case EVR_FL: // float single-precision - case EVR_OF: // other float (requires byte swapping) - { - ok = element.putFloat32(boost::lexical_cast(*decoded)).good(); - break; - } - - case EVR_FD: // float double-precision -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_OD: // other double (requires byte-swapping) -#endif - { - ok = element.putFloat64(boost::lexical_cast(*decoded)).good(); - break; - } - - - /** - * Sequence types, should never occur at this point. - **/ - - case EVR_SQ: // sequence of items - { - ok = false; - break; - } - - - /** - * Internal to DCMTK. - **/ - - case EVR_ox: // OB or OW depending on context - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - default: - break; - } - } - catch (boost::bad_lexical_cast&) - { - ok = false; - } - - if (!ok) - { - DicomTag tag(element.getTag().getGroup(), element.getTag().getElement()); - throw OrthancException(ErrorCode_BadFileFormat, - "While creating a DICOM instance, tag (" + tag.Format() + - ") has out-of-range value: \"" + (*decoded) + "\""); - } - } - - - DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag, - const Json::Value& value, - bool decodeDataUriScheme, - Encoding dicomEncoding, - const std::string& privateCreator) - { - std::unique_ptr element; - - switch (value.type()) - { - case Json::stringValue: - element.reset(CreateElementForTag(tag, privateCreator)); - FillElementWithString(*element, value.asString(), decodeDataUriScheme, dicomEncoding); - break; - - case Json::nullValue: - element.reset(CreateElementForTag(tag, privateCreator)); - FillElementWithString(*element, "", decodeDataUriScheme, dicomEncoding); - break; - - case Json::arrayValue: - { - DcmTag key(tag.GetGroup(), tag.GetElement()); - if (key.getEVR() != EVR_SQ) - { - throw OrthancException(ErrorCode_BadParameterType, "Bad Parameter type for tag " + tag.Format()); - } - - DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key); - element.reset(sequence); - - for (Json::Value::ArrayIndex i = 0; i < value.size(); i++) - { - std::unique_ptr item(new DcmItem); - - switch (value[i].type()) - { - case Json::objectValue: - { - Json::Value::Members members = value[i].getMemberNames(); - for (Json::Value::ArrayIndex j = 0; j < members.size(); j++) - { - item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding, privateCreator)); - } - break; - } - - case Json::arrayValue: - { - // Lua cannot disambiguate between an empty dictionary - // and an empty array - if (value[i].size() != 0) - { - throw OrthancException(ErrorCode_BadParameterType); - } - break; - } - - default: - throw OrthancException(ErrorCode_BadParameterType); - } - - sequence->append(item.release()); - } - - break; - } - - default: - throw OrthancException(ErrorCode_BadParameterType, "Bad Parameter type for tag " + tag.Format()); - } - - return element.release(); - } - - - DcmPixelSequence* FromDcmtkBridge::GetPixelSequence(DcmDataset& dataset) - { - DcmElement *element = NULL; - if (!dataset.findAndGetElement(DCM_PixelData, element).good()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - DcmPixelData& pixelData = dynamic_cast(*element); - - E_TransferSyntax repType; - const DcmRepresentationParameter *repParam = NULL; - pixelData.getCurrentRepresentationKey(repType, repParam); - - DcmPixelSequence* pixelSequence = NULL; - if (!pixelData.getEncapsulatedRepresentation(repType, repParam, pixelSequence).good()) - { - return NULL; - } - else - { - return pixelSequence; - } - } - - - Encoding FromDcmtkBridge::ExtractEncoding(const Json::Value& json, - Encoding defaultEncoding) - { - if (json.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - Encoding encoding = defaultEncoding; - - const Json::Value::Members tags = json.getMemberNames(); - - // Look for SpecificCharacterSet (0008,0005) in the JSON file - for (size_t i = 0; i < tags.size(); i++) - { - DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); - if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - const Json::Value& value = json[tags[i]]; - if (value.type() != Json::stringValue || - (value.asString().length() != 0 && - !GetDicomEncoding(encoding, value.asCString()))) - { - throw OrthancException(ErrorCode_BadRequest, - "Unknown encoding while creating DICOM from JSON: " + - value.toStyledString()); - } - - if (value.asString().length() == 0) - { - return defaultEncoding; - } - } - } - - return encoding; - } - - - static void SetString(DcmDataset& target, - const DcmTag& tag, - const std::string& value) - { - if (!target.putAndInsertString(tag, value.c_str()).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - DcmDataset* FromDcmtkBridge::FromJson(const Json::Value& json, // Encoded using UTF-8 - bool generateIdentifiers, - bool decodeDataUriScheme, - Encoding defaultEncoding, - const std::string& privateCreator) - { - std::unique_ptr result(new DcmDataset); - Encoding encoding = ExtractEncoding(json, defaultEncoding); - - SetString(*result, DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(encoding)); - - const Json::Value::Members tags = json.getMemberNames(); - - bool hasPatientId = false; - bool hasStudyInstanceUid = false; - bool hasSeriesInstanceUid = false; - bool hasSopInstanceUid = false; - - for (size_t i = 0; i < tags.size(); i++) - { - DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); - const Json::Value& value = json[tags[i]]; - - if (tag == DICOM_TAG_PATIENT_ID) - { - hasPatientId = true; - } - else if (tag == DICOM_TAG_STUDY_INSTANCE_UID) - { - hasStudyInstanceUid = true; - } - else if (tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - hasSeriesInstanceUid = true; - } - else if (tag == DICOM_TAG_SOP_INSTANCE_UID) - { - hasSopInstanceUid = true; - } - - if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - std::unique_ptr element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding, privateCreator)); - const DcmTagKey& tag = element->getTag(); - - result->findAndDeleteElement(tag); - - DcmElement* tmp = element.release(); - if (!result->insert(tmp, false, false).good()) - { - delete tmp; - throw OrthancException(ErrorCode_InternalError); - } - } - } - - if (!hasPatientId && - generateIdentifiers) - { - SetString(*result, DCM_PatientID, GenerateUniqueIdentifier(ResourceType_Patient)); - } - - if (!hasStudyInstanceUid && - generateIdentifiers) - { - SetString(*result, DCM_StudyInstanceUID, GenerateUniqueIdentifier(ResourceType_Study)); - } - - if (!hasSeriesInstanceUid && - generateIdentifiers) - { - SetString(*result, DCM_SeriesInstanceUID, GenerateUniqueIdentifier(ResourceType_Series)); - } - - if (!hasSopInstanceUid && - generateIdentifiers) - { - SetString(*result, DCM_SOPInstanceUID, GenerateUniqueIdentifier(ResourceType_Instance)); - } - - return result.release(); - } - - - DcmFileFormat* FromDcmtkBridge::LoadFromMemoryBuffer(const void* buffer, - size_t size) - { - DcmInputBufferStream is; - if (size > 0) - { - is.setBuffer(buffer, size); - } - is.setEos(); - - std::unique_ptr result(new DcmFileFormat); - - result->transferInit(); - - /** - * New in Orthanc 1.6.0: The "size" is given as an argument to the - * "read()" method. This can avoid huge memory consumption if - * parsing an invalid DICOM file, which can notably been observed - * by executing the integration test "test_upload_compressed" on - * valgrind running Orthanc. - **/ - if (!result->read(is, EXS_Unknown, EGL_noChange, size).good()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot parse an invalid DICOM file (size: " + - boost::lexical_cast(size) + " bytes)"); - } - - result->loadAllDataIntoMemory(); - result->transferEnd(); - - return result.release(); - } - - - void FromDcmtkBridge::FromJson(DicomMap& target, - const Json::Value& source) - { - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - target.Clear(); - - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& value = source[members[i]]; - - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - target.SetValue(ParseTag(members[i]), value.asString(), false); - } - } - - - void FromDcmtkBridge::ChangeStringEncoding(DcmItem& dataset, - Encoding source, - bool hasSourceCodeExtensions, - Encoding target) - { - // Recursive exploration of a dataset to change the encoding of - // each string-like element - - if (source == target) - { - return; - } - - for (unsigned long i = 0; i < dataset.card(); i++) - { - DcmElement* element = dataset.getElement(i); - if (element) - { - if (element->isLeaf()) - { - char *c = NULL; - if (element->isaString() && - element->getString(c).good() && - c != NULL) - { - std::string a = Toolbox::ConvertToUtf8(c, source, hasSourceCodeExtensions); - std::string b = Toolbox::ConvertFromUtf8(a, target); - element->putString(b.c_str()); - } - } - else - { - // "All subclasses of DcmElement except for DcmSequenceOfItems - // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset - // etc. are not." The following dynamic_cast is thus OK. - DcmSequenceOfItems& sequence = dynamic_cast(*element); - - for (unsigned long j = 0; j < sequence.card(); j++) - { - ChangeStringEncoding(*sequence.getItem(j), source, hasSourceCodeExtensions, target); - } - } - } - } - } - - -#if ORTHANC_ENABLE_LUA == 1 - void FromDcmtkBridge::ExecuteToDicom(DicomMap& target, - LuaFunctionCall& call) - { - Json::Value output; - call.ExecuteToJson(output, true /* keep strings */); - - target.Clear(); - - if (output.type() == Json::arrayValue && - output.size() == 0) - { - // This case happens for empty tables - return; - } - - if (output.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_LuaBadOutput, - "Lua: The script must return a table"); - } - - Json::Value::Members members = output.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - if (output[members[i]].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_LuaBadOutput, - "Lua: The script must return a table " - "mapping names of DICOM tags to strings"); - } - - DicomTag tag(ParseTag(members[i])); - target.SetValue(tag, output[members[i]].asString(), false); - } - } -#endif - - - void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, - DcmItem& dataset, - const std::set& ignoreTagLength) - { - ExtractDicomSummary(target, dataset, - ORTHANC_MAXIMUM_TAG_LENGTH, - GetDefaultDicomEncoding(), ignoreTagLength); - } - - - void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, - DcmDataset& dataset, - const std::set& ignoreTagLength) - { - ExtractDicomAsJson(target, dataset, - DicomToJsonFormat_Full, - DicomToJsonFlags_Default, - ORTHANC_MAXIMUM_TAG_LENGTH, - GetDefaultDicomEncoding(), - ignoreTagLength); - } - - - void FromDcmtkBridge::InitializeCodecs() - { -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - LOG(INFO) << "Registering JPEG Lossless codecs in DCMTK"; - DJLSDecoderRegistration::registerCodecs(); -# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - DJLSEncoderRegistration::registerCodecs(); -# endif -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - LOG(INFO) << "Registering JPEG codecs in DCMTK"; - DJDecoderRegistration::registerCodecs(); -# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - DJEncoderRegistration::registerCodecs(); -# endif -#endif - - LOG(INFO) << "Registering RLE codecs in DCMTK"; - DcmRLEDecoderRegistration::registerCodecs(); -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - DcmRLEEncoderRegistration::registerCodecs(); -#endif - } - - - void FromDcmtkBridge::FinalizeCodecs() - { -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - // Unregister JPEG-LS codecs - DJLSDecoderRegistration::cleanup(); -# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - DJLSEncoderRegistration::cleanup(); -# endif -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - // Unregister JPEG codecs - DJDecoderRegistration::cleanup(); -# if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - DJEncoderRegistration::cleanup(); -# endif -#endif - - DcmRLEDecoderRegistration::cleanup(); -#if ORTHANC_ENABLE_DCMTK_TRANSCODING == 1 - DcmRLEEncoderRegistration::cleanup(); -#endif - } - - - - // Forward declaration - static void ApplyVisitorToElement(DcmElement& element, - ITagVisitor& visitor, - const std::vector& parentTags, - const std::vector& parentIndexes, - Encoding encoding, - bool hasCodeExtensions); - - static void ApplyVisitorToDataset(DcmItem& dataset, - ITagVisitor& visitor, - const std::vector& parentTags, - const std::vector& parentIndexes, - Encoding encoding, - bool hasCodeExtensions) - { - assert(parentTags.size() == parentIndexes.size()); - - for (unsigned long i = 0; i < dataset.card(); i++) - { - DcmElement* element = dataset.getElement(i); - if (element == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - ApplyVisitorToElement(*element, visitor, parentTags, parentIndexes, encoding, hasCodeExtensions); - } - } - } - - - static void ApplyVisitorToLeaf(DcmElement& element, - ITagVisitor& visitor, - const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - Encoding encoding, - bool hasCodeExtensions) - { - // TODO - Merge this function, that is more recent, with ConvertLeafElement() - - assert(element.isLeaf()); - - DcmEVR evr = element.getTag().getEVR(); - - - /** - * Fix the EVR for types internal to DCMTK - **/ - - if (evr == EVR_ox) // OB or OW depending on context - { - evr = EVR_OB; - } - - if (evr == EVR_UNKNOWN || // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - evr == EVR_UNKNOWN2B) // used internally for elements with unknown VR with 2-byte length field in explicit VR - { - evr = EVR_UN; - } - - const ValueRepresentation vr = FromDcmtkBridge::Convert(evr); - - - /** - * Deal with binary data (including PixelData). - **/ - - if (evr == EVR_OB || // other byte - evr == EVR_OW || // other word - evr == EVR_UN) // unknown value representation - { - Uint16* data16 = NULL; - Uint8* data = NULL; - - if (evr == EVR_OW && - element.getUint16Array(data16) == EC_Normal) - { - visitor.VisitBinary(parentTags, parentIndexes, tag, vr, data16, element.getLength()); - } - else if (evr != EVR_OW && - element.getUint8Array(data) == EC_Normal) - { - visitor.VisitBinary(parentTags, parentIndexes, tag, vr, data, element.getLength()); - } - else - { - visitor.VisitNotSupported(parentTags, parentIndexes, tag, vr); - } - - return; // We're done - } - - - /** - * Deal with plain strings (and convert them to UTF-8) - **/ - - char *c = NULL; - if (element.isaString() && - element.getString(c).good()) - { - std::string utf8; - - if (c != NULL) // This case corresponds to the empty string - { - if (element.getTag() == DCM_SpecificCharacterSet) - { - utf8.assign(c); - } - else - { - std::string s(c); - utf8 = Toolbox::ConvertToUtf8(s, encoding, hasCodeExtensions); - } - } - - std::string newValue; - ITagVisitor::Action action = visitor.VisitString - (newValue, parentTags, parentIndexes, tag, vr, utf8); - - switch (action) - { - case ITagVisitor::Action_None: - break; - - case ITagVisitor::Action_Replace: - { - std::string s = Toolbox::ConvertFromUtf8(newValue, encoding); - if (element.putString(s.c_str()) != EC_Normal) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot replace value of tag: " + tag.Format()); - } - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - return; // We're done - } - - - try - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - switch (evr) - { - - /** - * Plain string values. - **/ - - case EVR_DS: // decimal string - case EVR_IS: // integer string - case EVR_AS: // age string - case EVR_DA: // date string - case EVR_DT: // date time string - case EVR_TM: // time string - case EVR_AE: // application entity title - case EVR_CS: // code string - case EVR_SH: // short string - case EVR_LO: // long string - case EVR_ST: // short text - case EVR_LT: // long text - case EVR_UT: // unlimited text - case EVR_PN: // person name - case EVR_UI: // unique identifier - { - Uint8* data = NULL; - - if (element.getUint8Array(data) == EC_Normal) - { - const Uint32 length = element.getLength(); - Uint32 l = 0; - while (l < length && - data[l] != 0) - { - l++; - } - - if (l == length) - { - // Not a null-terminated plain string - visitor.VisitNotSupported(parentTags, parentIndexes, tag, vr); - } - else - { - std::string ignored; - std::string s(reinterpret_cast(data), l); - ITagVisitor::Action action = visitor.VisitString - (ignored, parentTags, parentIndexes, tag, vr, - Toolbox::ConvertToUtf8(s, encoding, hasCodeExtensions)); - - if (action != ITagVisitor::Action_None) - { - LOG(WARNING) << "Cannot replace this string tag: " - << FromDcmtkBridge::GetTagName(element) - << " (" << tag.Format() << ")"; - } - } - } - else - { - visitor.VisitNotSupported(parentTags, parentIndexes, tag, vr); - } - - return; - } - - /** - * Numeric types - **/ - - case EVR_SL: // signed long - { - DcmSignedLong& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - Sint32 f; - if (content.getSint32(f, i).good()) - { - values.push_back(f); - } - } - - visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); - break; - } - - case EVR_SS: // signed short - { - DcmSignedShort& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - Sint16 f; - if (content.getSint16(f, i).good()) - { - values.push_back(f); - } - } - - visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); - break; - } - - case EVR_UL: // unsigned long -#if DCMTK_VERSION_NUMBER >= 362 - case EVR_OL: -#endif - { - DcmUnsignedLong& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - Uint32 f; - if (content.getUint32(f, i).good()) - { - values.push_back(f); - } - } - - visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); - break; - } - - case EVR_US: // unsigned short - { - DcmUnsignedShort& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - Uint16 f; - if (content.getUint16(f, i).good()) - { - values.push_back(f); - } - } - - visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values); - break; - } - - case EVR_FL: // float single-precision - case EVR_OF: - { - DcmFloatingPointSingle& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - Float32 f; - if (content.getFloat32(f, i).good()) - { - values.push_back(f); - } - } - - visitor.VisitDoubles(parentTags, parentIndexes, tag, vr, values); - break; - } - - case EVR_FD: // float double-precision -#if DCMTK_VERSION_NUMBER >= 361 - case EVR_OD: -#endif - { - DcmFloatingPointDouble& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - Float64 f; - if (content.getFloat64(f, i).good()) - { - values.push_back(f); - } - } - - visitor.VisitDoubles(parentTags, parentIndexes, tag, vr, values); - break; - } - - - /** - * Attribute tag. - **/ - - case EVR_AT: - { - DcmAttributeTag& content = dynamic_cast(element); - - std::vector values; - values.reserve(content.getVM()); - - for (unsigned long i = 0; i < content.getVM(); i++) - { - DcmTagKey f; - if (content.getTagVal(f, i).good()) - { - DicomTag t(f.getGroup(), f.getElement()); - values.push_back(t); - } - } - - assert(vr == ValueRepresentation_AttributeTag); - visitor.VisitAttributes(parentTags, parentIndexes, tag, values); - break; - } - - - /** - * Sequence types, should never occur at this point because of - * "element.isLeaf()". - **/ - - case EVR_SQ: // sequence of items - { - return; - } - - - /** - * Internal to DCMTK. - **/ - - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - { - visitor.VisitNotSupported(parentTags, parentIndexes, tag, vr); - return; - } - - - /** - * Default case. - **/ - - default: - return; - } - } - catch (boost::bad_lexical_cast&) - { - return; - } - catch (std::bad_cast&) - { - return; - } - } - - - static void ApplyVisitorToElement(DcmElement& element, - ITagVisitor& visitor, - const std::vector& parentTags, - const std::vector& parentIndexes, - Encoding encoding, - bool hasCodeExtensions) - { - assert(parentTags.size() == parentIndexes.size()); - - DicomTag tag(FromDcmtkBridge::Convert(element.getTag())); - - if (element.isLeaf()) - { - ApplyVisitorToLeaf(element, visitor, parentTags, parentIndexes, tag, encoding, hasCodeExtensions); - } - else - { - // "All subclasses of DcmElement except for DcmSequenceOfItems - // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset - // etc. are not." The following dynamic_cast is thus OK. - DcmSequenceOfItems& sequence = dynamic_cast(element); - - if (sequence.card() == 0) - { - visitor.VisitEmptySequence(parentTags, parentIndexes, tag); - } - else - { - std::vector tags = parentTags; - std::vector indexes = parentIndexes; - tags.push_back(tag); - indexes.push_back(0); - - for (unsigned long i = 0; i < sequence.card(); i++) - { - indexes.back() = static_cast(i); - DcmItem* child = sequence.getItem(i); - ApplyVisitorToDataset(*child, visitor, tags, indexes, encoding, hasCodeExtensions); - } - } - } - } - - - void FromDcmtkBridge::Apply(DcmItem& dataset, - ITagVisitor& visitor, - Encoding defaultEncoding) - { - std::vector parentTags; - std::vector parentIndexes; - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); - ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding, hasCodeExtensions); - } - - - - bool FromDcmtkBridge::LookupOrthancTransferSyntax(DicomTransferSyntax& target, - DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DcmDataset& dataset = *dicom.getDataset(); - - E_TransferSyntax xfer = dataset.getCurrentXfer(); - if (xfer == EXS_Unknown) - { - dataset.updateOriginalXfer(); - xfer = dataset.getOriginalXfer(); - if (xfer == EXS_Unknown) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot determine the transfer syntax of the DICOM instance"); - } - } - - return FromDcmtkBridge::LookupOrthancTransferSyntax(target, xfer); - } -} - - -#include "./FromDcmtkBridge_TransferSyntaxes.impl.h" diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,284 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ITagVisitor.h" -#include "../DicomFormat/DicomElement.h" -#include "../DicomFormat/DicomMap.h" - -#include -#include -#include -#include -#include - -#if !defined(ORTHANC_ENABLE_LUA) -# error The macro ORTHANC_ENABLE_LUA must be defined -#endif - -#if ORTHANC_ENABLE_DCMTK != 1 -# error The macro ORTHANC_ENABLE_DCMTK must be set to 1 -#endif - -#if ORTHANC_BUILD_UNIT_TESTS == 1 -# include -#endif - -#if ORTHANC_ENABLE_LUA == 1 -# include "../Lua/LuaFunctionCall.h" -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG) -# error The macro ORTHANC_ENABLE_DCMTK_JPEG must be defined -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) -# error The macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined -#endif - - -namespace Orthanc -{ - class FromDcmtkBridge : public boost::noncopyable - { -#if ORTHANC_BUILD_UNIT_TESTS == 1 - FRIEND_TEST(FromDcmtkBridge, FromJson); -#endif - - friend class ParsedDicomFile; - - private: - FromDcmtkBridge(); // Pure static class - - static void ExtractDicomSummary(DicomMap& target, - DcmItem& dataset, - unsigned int maxStringLength, - Encoding defaultEncoding, - const std::set& ignoreTagLength); - - static void DatasetToJson(Json::Value& parent, - DcmItem& item, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding, - bool hasCodeExtensions, - const std::set& ignoreTagLength); - - static void ElementToJson(Json::Value& parent, - DcmElement& element, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding dicomEncoding, - bool hasCodeExtensions, - const std::set& ignoreTagLength); - - static void ExtractDicomAsJson(Json::Value& target, - DcmDataset& dataset, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding defaultEncoding, - const std::set& ignoreTagLength); - - static void ChangeStringEncoding(DcmItem& dataset, - Encoding source, - bool hasSourceCodeExtensions, - Encoding target); - - public: - static void InitializeDictionary(bool loadPrivateDictionary); - - static void RegisterDictionaryTag(const DicomTag& tag, - ValueRepresentation vr, - const std::string& name, - unsigned int minMultiplicity, - unsigned int maxMultiplicity, - const std::string& privateCreator); - - static Encoding DetectEncoding(bool& hasCodeExtensions, - DcmItem& dataset, - Encoding defaultEncoding); - - static Encoding DetectEncoding(DcmItem& dataset, - Encoding defaultEncoding) - { - // Compatibility wrapper for Orthanc <= 1.5.4 - bool hasCodeExtensions; // ignored - return DetectEncoding(hasCodeExtensions, dataset, defaultEncoding); - } - - static DicomTag Convert(const DcmTag& tag); - - static DicomTag GetTag(const DcmElement& element); - - static bool IsUnknownTag(const DicomTag& tag); - - static DicomValue* ConvertLeafElement(DcmElement& element, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding, - bool hasCodeExtensions, - const std::set& ignoreTagLength); - - static void ExtractHeaderAsJson(Json::Value& target, - DcmMetaInfo& header, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength); - - static std::string GetTagName(const DicomTag& tag, - const std::string& privateCreator); - - static std::string GetTagName(const DcmElement& element); - - static std::string GetTagName(const DicomElement& element) - { - return GetTagName(element.GetTag(), ""); - } - - static DicomTag ParseTag(const char* name); - - static DicomTag ParseTag(const std::string& name) - { - return ParseTag(name.c_str()); - } - - static bool HasTag(const DicomMap& fields, - const std::string& tagName) - { - return fields.HasTag(ParseTag(tagName)); - } - - static const DicomValue& GetValue(const DicomMap& fields, - const std::string& tagName) - { - return fields.GetValue(ParseTag(tagName)); - } - - static void SetValue(DicomMap& target, - const std::string& tagName, - DicomValue* value) - { - const DicomTag tag = ParseTag(tagName); - target.SetValueInternal(tag.GetGroup(), tag.GetElement(), value); - } - - static void ToJson(Json::Value& result, - const DicomMap& values, - bool simplify); - - static std::string GenerateUniqueIdentifier(ResourceType level); - - static bool SaveToMemoryBuffer(std::string& buffer, - DcmDataset& dataSet); - - static bool Transcode(DcmFileFormat& dicom, - DicomTransferSyntax syntax, - const DcmRepresentationParameter* representation); - - static ValueRepresentation Convert(DcmEVR vr); - - static ValueRepresentation LookupValueRepresentation(const DicomTag& tag); - - static DcmElement* CreateElementForTag(const DicomTag& tag, - const std::string& privateCreator); - - static void FillElementWithString(DcmElement& element, - const std::string& utf8alue, // Encoded using UTF-8 - bool decodeDataUriScheme, - Encoding dicomEncoding); - - static DcmElement* FromJson(const DicomTag& tag, - const Json::Value& element, // Encoded using UTF-8 - bool decodeDataUriScheme, - Encoding dicomEncoding, - const std::string& privateCreator); - - static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset); - - static Encoding ExtractEncoding(const Json::Value& json, - Encoding defaultEncoding); - - static DcmDataset* FromJson(const Json::Value& json, // Encoded using UTF-8 - bool generateIdentifiers, - bool decodeDataUriScheme, - Encoding defaultEncoding, - const std::string& privateCreator); - - static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer, - size_t size); - - static void FromJson(DicomMap& values, - const Json::Value& result); - -#if ORTHANC_ENABLE_LUA == 1 - static void ExecuteToDicom(DicomMap& target, - LuaFunctionCall& call); -#endif - - static void ExtractDicomSummary(DicomMap& target, - DcmItem& dataset, - const std::set& ignoreTagLength); - - static void ExtractDicomSummary(DicomMap& target, - DcmItem& dataset) - { - std::set none; - ExtractDicomSummary(target, dataset, none); - } - - static void ExtractDicomAsJson(Json::Value& target, - DcmDataset& dataset, - const std::set& ignoreTagLength); - - static void InitializeCodecs(); - - static void FinalizeCodecs(); - - static void Apply(DcmItem& dataset, - ITagVisitor& visitor, - Encoding defaultEncoding); - - static bool LookupDcmtkTransferSyntax(E_TransferSyntax& target, - DicomTransferSyntax source); - - static bool LookupOrthancTransferSyntax(DicomTransferSyntax& target, - E_TransferSyntax source); - - static bool LookupOrthancTransferSyntax(DicomTransferSyntax& target, - DcmFileFormat& dicom); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/FromDcmtkBridge_TransferSyntaxes.impl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,549 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -// This file is autogenerated by "../Resources/GenerateTransferSyntaxes.py" - -namespace Orthanc -{ - bool FromDcmtkBridge::LookupDcmtkTransferSyntax(E_TransferSyntax& target, - DicomTransferSyntax source) - { - switch (source) - { - case DicomTransferSyntax_LittleEndianImplicit: - target = EXS_LittleEndianImplicit; - return true; - - case DicomTransferSyntax_LittleEndianExplicit: - target = EXS_LittleEndianExplicit; - return true; - - case DicomTransferSyntax_DeflatedLittleEndianExplicit: - target = EXS_DeflatedLittleEndianExplicit; - return true; - - case DicomTransferSyntax_BigEndianExplicit: - target = EXS_BigEndianExplicit; - return true; - - case DicomTransferSyntax_JPEGProcess1: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess1TransferSyntax; -# else - target = EXS_JPEGProcess1; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess2_4: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess2_4TransferSyntax; -# else - target = EXS_JPEGProcess2_4; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess3_5: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess3_5TransferSyntax; -# else - target = EXS_JPEGProcess3_5; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess6_8: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess6_8TransferSyntax; -# else - target = EXS_JPEGProcess6_8; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess7_9: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess7_9TransferSyntax; -# else - target = EXS_JPEGProcess7_9; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess10_12: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess10_12TransferSyntax; -# else - target = EXS_JPEGProcess10_12; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess11_13: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess11_13TransferSyntax; -# else - target = EXS_JPEGProcess11_13; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess14: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess14TransferSyntax; -# else - target = EXS_JPEGProcess14; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess15: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess15TransferSyntax; -# else - target = EXS_JPEGProcess15; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess16_18: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess16_18TransferSyntax; -# else - target = EXS_JPEGProcess16_18; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess17_19: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess17_19TransferSyntax; -# else - target = EXS_JPEGProcess17_19; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess20_22: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess20_22TransferSyntax; -# else - target = EXS_JPEGProcess20_22; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess21_23: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess21_23TransferSyntax; -# else - target = EXS_JPEGProcess21_23; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess24_26: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess24_26TransferSyntax; -# else - target = EXS_JPEGProcess24_26; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess25_27: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess25_27TransferSyntax; -# else - target = EXS_JPEGProcess25_27; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess28: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess28TransferSyntax; -# else - target = EXS_JPEGProcess28; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess29: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess29TransferSyntax; -# else - target = EXS_JPEGProcess29; -# endif - return true; - - case DicomTransferSyntax_JPEGProcess14SV1: -# if DCMTK_VERSION_NUMBER <= 360 - target = EXS_JPEGProcess14SV1TransferSyntax; -# else - target = EXS_JPEGProcess14SV1; -# endif - return true; - - case DicomTransferSyntax_JPEGLSLossless: - target = EXS_JPEGLSLossless; - return true; - - case DicomTransferSyntax_JPEGLSLossy: - target = EXS_JPEGLSLossy; - return true; - - case DicomTransferSyntax_JPEG2000LosslessOnly: - target = EXS_JPEG2000LosslessOnly; - return true; - - case DicomTransferSyntax_JPEG2000: - target = EXS_JPEG2000; - return true; - - case DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly: - target = EXS_JPEG2000MulticomponentLosslessOnly; - return true; - - case DicomTransferSyntax_JPEG2000Multicomponent: - target = EXS_JPEG2000Multicomponent; - return true; - - case DicomTransferSyntax_JPIPReferenced: - target = EXS_JPIPReferenced; - return true; - - case DicomTransferSyntax_JPIPReferencedDeflate: - target = EXS_JPIPReferencedDeflate; - return true; - - case DicomTransferSyntax_MPEG2MainProfileAtMainLevel: - target = EXS_MPEG2MainProfileAtMainLevel; - return true; - - case DicomTransferSyntax_MPEG2MainProfileAtHighLevel: - target = EXS_MPEG2MainProfileAtHighLevel; - return true; - -#if DCMTK_VERSION_NUMBER >= 361 - case DicomTransferSyntax_MPEG4HighProfileLevel4_1: - target = EXS_MPEG4HighProfileLevel4_1; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1: - target = EXS_MPEG4BDcompatibleHighProfileLevel4_1; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo: - target = EXS_MPEG4HighProfileLevel4_2_For2DVideo; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo: - target = EXS_MPEG4HighProfileLevel4_2_For3DVideo; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2: - target = EXS_MPEG4StereoHighProfileLevel4_2; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 362 - case DicomTransferSyntax_HEVCMainProfileLevel5_1: - target = EXS_HEVCMainProfileLevel5_1; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 362 - case DicomTransferSyntax_HEVCMain10ProfileLevel5_1: - target = EXS_HEVCMain10ProfileLevel5_1; - return true; -#endif - - case DicomTransferSyntax_RLELossless: - target = EXS_RLELossless; - return true; - - default: - return false; - } - } - - - bool FromDcmtkBridge::LookupOrthancTransferSyntax(DicomTransferSyntax& target, - E_TransferSyntax source) - { - switch (source) - { - case EXS_LittleEndianImplicit: - target = DicomTransferSyntax_LittleEndianImplicit; - return true; - - case EXS_LittleEndianExplicit: - target = DicomTransferSyntax_LittleEndianExplicit; - return true; - - case EXS_DeflatedLittleEndianExplicit: - target = DicomTransferSyntax_DeflatedLittleEndianExplicit; - return true; - - case EXS_BigEndianExplicit: - target = DicomTransferSyntax_BigEndianExplicit; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess1TransferSyntax: -# else - case EXS_JPEGProcess1: -# endif - target = DicomTransferSyntax_JPEGProcess1; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess2_4TransferSyntax: -# else - case EXS_JPEGProcess2_4: -# endif - target = DicomTransferSyntax_JPEGProcess2_4; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess3_5TransferSyntax: -# else - case EXS_JPEGProcess3_5: -# endif - target = DicomTransferSyntax_JPEGProcess3_5; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess6_8TransferSyntax: -# else - case EXS_JPEGProcess6_8: -# endif - target = DicomTransferSyntax_JPEGProcess6_8; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess7_9TransferSyntax: -# else - case EXS_JPEGProcess7_9: -# endif - target = DicomTransferSyntax_JPEGProcess7_9; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess10_12TransferSyntax: -# else - case EXS_JPEGProcess10_12: -# endif - target = DicomTransferSyntax_JPEGProcess10_12; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess11_13TransferSyntax: -# else - case EXS_JPEGProcess11_13: -# endif - target = DicomTransferSyntax_JPEGProcess11_13; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess14TransferSyntax: -# else - case EXS_JPEGProcess14: -# endif - target = DicomTransferSyntax_JPEGProcess14; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess15TransferSyntax: -# else - case EXS_JPEGProcess15: -# endif - target = DicomTransferSyntax_JPEGProcess15; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess16_18TransferSyntax: -# else - case EXS_JPEGProcess16_18: -# endif - target = DicomTransferSyntax_JPEGProcess16_18; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess17_19TransferSyntax: -# else - case EXS_JPEGProcess17_19: -# endif - target = DicomTransferSyntax_JPEGProcess17_19; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess20_22TransferSyntax: -# else - case EXS_JPEGProcess20_22: -# endif - target = DicomTransferSyntax_JPEGProcess20_22; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess21_23TransferSyntax: -# else - case EXS_JPEGProcess21_23: -# endif - target = DicomTransferSyntax_JPEGProcess21_23; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess24_26TransferSyntax: -# else - case EXS_JPEGProcess24_26: -# endif - target = DicomTransferSyntax_JPEGProcess24_26; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess25_27TransferSyntax: -# else - case EXS_JPEGProcess25_27: -# endif - target = DicomTransferSyntax_JPEGProcess25_27; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess28TransferSyntax: -# else - case EXS_JPEGProcess28: -# endif - target = DicomTransferSyntax_JPEGProcess28; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess29TransferSyntax: -# else - case EXS_JPEGProcess29: -# endif - target = DicomTransferSyntax_JPEGProcess29; - return true; - -# if DCMTK_VERSION_NUMBER <= 360 - case EXS_JPEGProcess14SV1TransferSyntax: -# else - case EXS_JPEGProcess14SV1: -# endif - target = DicomTransferSyntax_JPEGProcess14SV1; - return true; - - case EXS_JPEGLSLossless: - target = DicomTransferSyntax_JPEGLSLossless; - return true; - - case EXS_JPEGLSLossy: - target = DicomTransferSyntax_JPEGLSLossy; - return true; - - case EXS_JPEG2000LosslessOnly: - target = DicomTransferSyntax_JPEG2000LosslessOnly; - return true; - - case EXS_JPEG2000: - target = DicomTransferSyntax_JPEG2000; - return true; - - case EXS_JPEG2000MulticomponentLosslessOnly: - target = DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; - return true; - - case EXS_JPEG2000Multicomponent: - target = DicomTransferSyntax_JPEG2000Multicomponent; - return true; - - case EXS_JPIPReferenced: - target = DicomTransferSyntax_JPIPReferenced; - return true; - - case EXS_JPIPReferencedDeflate: - target = DicomTransferSyntax_JPIPReferencedDeflate; - return true; - - case EXS_MPEG2MainProfileAtMainLevel: - target = DicomTransferSyntax_MPEG2MainProfileAtMainLevel; - return true; - - case EXS_MPEG2MainProfileAtHighLevel: - target = DicomTransferSyntax_MPEG2MainProfileAtHighLevel; - return true; - -#if DCMTK_VERSION_NUMBER >= 361 - case EXS_MPEG4HighProfileLevel4_1: - target = DicomTransferSyntax_MPEG4HighProfileLevel4_1; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case EXS_MPEG4BDcompatibleHighProfileLevel4_1: - target = DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case EXS_MPEG4HighProfileLevel4_2_For2DVideo: - target = DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case EXS_MPEG4HighProfileLevel4_2_For3DVideo: - target = DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 361 - case EXS_MPEG4StereoHighProfileLevel4_2: - target = DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 362 - case EXS_HEVCMainProfileLevel5_1: - target = DicomTransferSyntax_HEVCMainProfileLevel5_1; - return true; -#endif - -#if DCMTK_VERSION_NUMBER >= 362 - case EXS_HEVCMain10ProfileLevel5_1: - target = DicomTransferSyntax_HEVCMain10ProfileLevel5_1; - return true; -#endif - - case EXS_RLELossless: - target = DicomTransferSyntax_RLELossless; - return true; - - default: - return false; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,438 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "IDicomTranscoder.h" - -#include "../OrthancException.h" -#include "FromDcmtkBridge.h" -#include "ParsedDicomFile.h" - -#include -#include - -namespace Orthanc -{ - IDicomTranscoder::TranscodingType IDicomTranscoder::GetTranscodingType(DicomTransferSyntax target, - DicomTransferSyntax source) - { - if (target == source) - { - return TranscodingType_Lossless; - } - else if (target == DicomTransferSyntax_LittleEndianImplicit || - target == DicomTransferSyntax_LittleEndianExplicit || - target == DicomTransferSyntax_BigEndianExplicit || - target == DicomTransferSyntax_DeflatedLittleEndianExplicit || - target == DicomTransferSyntax_JPEGProcess14 || - target == DicomTransferSyntax_JPEGProcess14SV1 || - target == DicomTransferSyntax_JPEGLSLossless || - target == DicomTransferSyntax_JPEG2000LosslessOnly || - target == DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly) - { - return TranscodingType_Lossless; - } - else if (target == DicomTransferSyntax_JPEGProcess1 || - target == DicomTransferSyntax_JPEGProcess2_4 || - target == DicomTransferSyntax_JPEGLSLossy || - target == DicomTransferSyntax_JPEG2000 || - target == DicomTransferSyntax_JPEG2000Multicomponent) - { - return TranscodingType_Lossy; - } - else - { - return TranscodingType_Unknown; - } - } - - - std::string IDicomTranscoder::GetSopInstanceUid(DcmFileFormat& dicom) - { - if (dicom.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DcmDataset& dataset = *dicom.getDataset(); - - const char* v = NULL; - - if (dataset.findAndGetString(DCM_SOPInstanceUID, v).good() && - v != NULL) - { - return std::string(v); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, "File without SOP instance UID"); - } - } - - - void IDicomTranscoder::CheckTranscoding(IDicomTranscoder::DicomImage& transcoded, - DicomTransferSyntax sourceSyntax, - const std::string& sourceSopInstanceUid, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - DcmFileFormat& parsed = transcoded.GetParsed(); - - if (parsed.getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - std::string targetSopInstanceUid = GetSopInstanceUid(parsed); - - if (parsed.getDataset()->tagExists(DCM_PixelData)) - { - if (!allowNewSopInstanceUid && (targetSopInstanceUid != sourceSopInstanceUid)) - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - if (targetSopInstanceUid != sourceSopInstanceUid) - { - throw OrthancException(ErrorCode_InternalError, - "No pixel data: Transcoding must not change the SOP instance UID"); - } - } - - DicomTransferSyntax targetSyntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(targetSyntax, parsed)) - { - return; // Unknown transfer syntax, cannot do further test - } - - if (allowedSyntaxes.find(sourceSyntax) != allowedSyntaxes.end()) - { - // No transcoding should have happened - if (targetSopInstanceUid != sourceSopInstanceUid) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - if (allowedSyntaxes.find(targetSyntax) == allowedSyntaxes.end()) - { - throw OrthancException(ErrorCode_InternalError, "An incorrect output transfer syntax was chosen"); - } - - if (parsed.getDataset()->tagExists(DCM_PixelData)) - { - switch (GetTranscodingType(targetSyntax, sourceSyntax)) - { - case TranscodingType_Lossy: - if (targetSopInstanceUid == sourceSopInstanceUid) - { - throw OrthancException(ErrorCode_InternalError); - } - break; - - case TranscodingType_Lossless: - if (targetSopInstanceUid != sourceSopInstanceUid) - { - throw OrthancException(ErrorCode_InternalError); - } - break; - - default: - break; - } - } - } - - - void IDicomTranscoder::DicomImage::Parse() - { - if (parsed_.get() != NULL) - { - // Already parsed - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (buffer_.get() != NULL) - { - if (isExternalBuffer_) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - parsed_.reset(FromDcmtkBridge::LoadFromMemoryBuffer( - buffer_->empty() ? NULL : buffer_->c_str(), buffer_->size())); - - if (parsed_.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - } - else if (isExternalBuffer_) - { - parsed_.reset(FromDcmtkBridge::LoadFromMemoryBuffer(externalBuffer_, externalSize_)); - - if (parsed_.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - else - { - // No buffer is available - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void IDicomTranscoder::DicomImage::Serialize() - { - if (parsed_.get() == NULL || - buffer_.get() != NULL || - isExternalBuffer_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (parsed_->getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - buffer_.reset(new std::string); - FromDcmtkBridge::SaveToMemoryBuffer(*buffer_, *parsed_->getDataset()); - } - } - - - IDicomTranscoder::DicomImage::DicomImage() : - isExternalBuffer_(false) - { - } - - - void IDicomTranscoder::DicomImage::Clear() - { - parsed_.reset(NULL); - buffer_.reset(NULL); - isExternalBuffer_ = false; - } - - - void IDicomTranscoder::DicomImage::AcquireParsed(ParsedDicomFile& parsed) - { - AcquireParsed(parsed.ReleaseDcmtkObject()); - } - - - void IDicomTranscoder::DicomImage::AcquireParsed(DcmFileFormat* parsed) - { - if (parsed == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else if (parsed->getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else if (parsed_.get() != NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parsed_.reset(parsed); - } - } - - - void IDicomTranscoder::DicomImage::AcquireParsed(DicomImage& other) - { - AcquireParsed(other.ReleaseParsed()); - } - - - void IDicomTranscoder::DicomImage::AcquireBuffer(std::string& buffer /* will be swapped */) - { - if (buffer_.get() != NULL || - isExternalBuffer_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - buffer_.reset(new std::string); - buffer_->swap(buffer); - } - } - - - void IDicomTranscoder::DicomImage::AcquireBuffer(DicomImage& other) - { - if (buffer_.get() != NULL || - isExternalBuffer_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (other.isExternalBuffer_) - { - assert(other.buffer_.get() == NULL); - isExternalBuffer_ = true; - externalBuffer_ = other.externalBuffer_; - externalSize_ = other.externalSize_; - } - else if (other.buffer_.get() != NULL) - { - buffer_.reset(other.buffer_.release()); - } - else - { - buffer_.reset(NULL); - } - } - - - void IDicomTranscoder::DicomImage::SetExternalBuffer(const void* buffer, - size_t size) - { - if (buffer_.get() != NULL || - isExternalBuffer_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - isExternalBuffer_ = true; - externalBuffer_ = buffer; - externalSize_ = size; - } - } - - - void IDicomTranscoder::DicomImage::SetExternalBuffer(const std::string& buffer) - { - SetExternalBuffer(buffer.empty() ? NULL : buffer.c_str(), buffer.size()); - } - - - DcmFileFormat& IDicomTranscoder::DicomImage::GetParsed() - { - if (parsed_.get() != NULL) - { - return *parsed_; - } - else if (buffer_.get() != NULL || - isExternalBuffer_) - { - Parse(); - return *parsed_; - } - else - { - throw OrthancException( - ErrorCode_BadSequenceOfCalls, - "AcquireParsed(), AcquireBuffer() or SetExternalBuffer() should have been called"); - } - } - - - DcmFileFormat* IDicomTranscoder::DicomImage::ReleaseParsed() - { - if (parsed_.get() != NULL) - { - buffer_.reset(NULL); - return parsed_.release(); - } - else if (buffer_.get() != NULL || - isExternalBuffer_) - { - Parse(); - buffer_.reset(NULL); - return parsed_.release(); - } - else - { - throw OrthancException( - ErrorCode_BadSequenceOfCalls, - "AcquireParsed(), AcquireBuffer() or SetExternalBuffer() should have been called"); - } - } - - - ParsedDicomFile* IDicomTranscoder::DicomImage::ReleaseAsParsedDicomFile() - { - return ParsedDicomFile::AcquireDcmtkObject(ReleaseParsed()); - } - - - const void* IDicomTranscoder::DicomImage::GetBufferData() - { - if (isExternalBuffer_) - { - assert(buffer_.get() == NULL); - return externalBuffer_; - } - else - { - if (buffer_.get() == NULL) - { - Serialize(); - } - - assert(buffer_.get() != NULL); - return buffer_->empty() ? NULL : buffer_->c_str(); - } - } - - - size_t IDicomTranscoder::DicomImage::GetBufferSize() - { - if (isExternalBuffer_) - { - assert(buffer_.get() == NULL); - return externalSize_; - } - else - { - if (buffer_.get() == NULL) - { - Serialize(); - } - - assert(buffer_.get() != NULL); - return buffer_->size(); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/IDicomTranscoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Compatibility.h" -#include "../Enumerations.h" - -#include -#include - -class DcmFileFormat; - -namespace Orthanc -{ - /** - * WARNING: This class might be called from several threads at - * once. Make sure to implement proper locking. - **/ - - class ParsedDicomFile; - - class IDicomTranscoder : public boost::noncopyable - { - public: - class DicomImage : public boost::noncopyable - { - private: - std::unique_ptr parsed_; - std::unique_ptr buffer_; - bool isExternalBuffer_; - const void* externalBuffer_; - size_t externalSize_; - - void Parse(); - - void Serialize(); - - DcmFileFormat* ReleaseParsed(); - - public: - DicomImage(); - - void Clear(); - - // Calling this method will invalidate the "ParsedDicomFile" object - void AcquireParsed(ParsedDicomFile& parsed); - - void AcquireParsed(DcmFileFormat* parsed); - - void AcquireParsed(DicomImage& other); - - void AcquireBuffer(std::string& buffer /* will be swapped */); - - void AcquireBuffer(DicomImage& other); - - void SetExternalBuffer(const void* buffer, - size_t size); - - void SetExternalBuffer(const std::string& buffer); - - DcmFileFormat& GetParsed(); - - ParsedDicomFile* ReleaseAsParsedDicomFile(); - - const void* GetBufferData(); - - size_t GetBufferSize(); - }; - - - protected: - enum TranscodingType - { - TranscodingType_Lossy, - TranscodingType_Lossless, - TranscodingType_Unknown - }; - - static TranscodingType GetTranscodingType(DicomTransferSyntax target, - DicomTransferSyntax source); - - static void CheckTranscoding(DicomImage& transcoded, - DicomTransferSyntax sourceSyntax, - const std::string& sourceSopInstanceUid, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid); - - public: - virtual ~IDicomTranscoder() - { - } - - virtual bool Transcode(DicomImage& target, - DicomImage& source /* in, "GetParsed()" possibly modified */, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; - - static std::string GetSopInstanceUid(DcmFileFormat& dicom); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,403 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeaders.h" -#include "DicomFrameIndex.h" - -#include "../../OrthancException.h" -#include "../../DicomFormat/DicomImageInformation.h" -#include "../FromDcmtkBridge.h" -#include "../../Endianness.h" -#include "DicomImageDecoder.h" - -#include - -#include -#include -#include - -namespace Orthanc -{ - class DicomFrameIndex::FragmentIndex : public DicomFrameIndex::IIndex - { - private: - DcmPixelSequence* pixelSequence_; - std::vector startFragment_; - std::vector countFragments_; - std::vector frameSize_; - - void GetOffsetTable(std::vector& table) - { - DcmPixelItem* item = NULL; - if (!pixelSequence_->getItem(item, 0).good() || - item == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - uint32_t length = item->getLength(); - if (length == 0) - { - // Degenerate case: Empty offset table means only one frame - // that overlaps all the fragments - table.resize(1); - table[0] = 0; - return; - } - - if (length % 4 != 0) - { - // Error: Each fragment is index with 4 bytes (uint32_t) - throw OrthancException(ErrorCode_BadFileFormat); - } - - uint8_t* content = NULL; - if (!item->getUint8Array(content).good() || - content == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - table.resize(length / 4); - - // The offset table is always in little endian in the DICOM - // file. Swap it to host endianness if needed. - const uint32_t* offset = reinterpret_cast(content); - for (size_t i = 0; i < table.size(); i++, offset++) - { - table[i] = le32toh(*offset); - } - } - - - public: - FragmentIndex(DcmPixelSequence* pixelSequence, - unsigned int countFrames) : - pixelSequence_(pixelSequence) - { - assert(pixelSequence != NULL); - - startFragment_.resize(countFrames); - countFragments_.resize(countFrames); - frameSize_.resize(countFrames); - - // The first fragment corresponds to the offset table - unsigned int countFragments = static_cast(pixelSequence_->card()); - if (countFragments < countFrames + 1) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - if (countFragments == countFrames + 1) - { - // Simple case: There is one fragment per frame. - - DcmObject* fragment = pixelSequence_->nextInContainer(NULL); // Skip the offset table - if (fragment == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - for (unsigned int i = 0; i < countFrames; i++) - { - fragment = pixelSequence_->nextInContainer(fragment); - startFragment_[i] = dynamic_cast(fragment); - frameSize_[i] = fragment->getLength(); - countFragments_[i] = 1; - } - - return; - } - - // Parse the offset table - std::vector offsetOfFrame; - GetOffsetTable(offsetOfFrame); - - if (offsetOfFrame.size() != countFrames || - offsetOfFrame[0] != 0) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - // Loop over the fragments (ignoring the offset table). This is - // an alternative, faster implementation to DCMTK's - // "DcmCodec::determineStartFragment()". - DcmObject* fragment = pixelSequence_->nextInContainer(NULL); - if (fragment == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - fragment = pixelSequence_->nextInContainer(fragment); // Skip the offset table - if (fragment == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - uint32_t offset = 0; - unsigned int currentFrame = 0; - startFragment_[0] = dynamic_cast(fragment); - - unsigned int currentFragment = 1; - while (fragment != NULL) - { - if (currentFrame + 1 < countFrames && - offset == offsetOfFrame[currentFrame + 1]) - { - currentFrame += 1; - startFragment_[currentFrame] = dynamic_cast(fragment); - } - - frameSize_[currentFrame] += fragment->getLength(); - countFragments_[currentFrame]++; - - // 8 bytes = overhead for the item tag and length field - offset += fragment->getLength() + 8; - - currentFragment++; - fragment = pixelSequence_->nextInContainer(fragment); - } - - if (currentFragment != countFragments || - currentFrame + 1 != countFrames || - fragment != NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - assert(startFragment_.size() == countFragments_.size() && - startFragment_.size() == frameSize_.size()); - } - - - virtual void GetRawFrame(std::string& frame, - unsigned int index) const - { - if (index >= startFragment_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - frame.resize(frameSize_[index]); - if (frame.size() == 0) - { - return; - } - - uint8_t* target = reinterpret_cast(&frame[0]); - - size_t offset = 0; - DcmPixelItem* fragment = startFragment_[index]; - for (unsigned int i = 0; i < countFragments_[index]; i++) - { - uint8_t* content = NULL; - if (!fragment->getUint8Array(content).good() || - content == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - assert(offset + fragment->getLength() <= frame.size()); - - memcpy(target + offset, content, fragment->getLength()); - offset += fragment->getLength(); - - fragment = dynamic_cast(pixelSequence_->nextInContainer(fragment)); - } - } - }; - - - - class DicomFrameIndex::UncompressedIndex : public DicomFrameIndex::IIndex - { - private: - uint8_t* pixelData_; - size_t frameSize_; - - public: - UncompressedIndex(DcmDataset& dataset, - unsigned int countFrames, - size_t frameSize) : - pixelData_(NULL), - frameSize_(frameSize) - { - size_t size = 0; - - DcmElement* e; - if (dataset.findAndGetElement(DCM_PixelData, e).good() && - e != NULL) - { - size = e->getLength(); - - if (size > 0) - { - pixelData_ = NULL; - if (!e->getUint8Array(pixelData_).good() || - pixelData_ == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - } - - if (size < frameSize_ * countFrames) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - virtual void GetRawFrame(std::string& frame, - unsigned int index) const - { - frame.resize(frameSize_); - if (frameSize_ > 0) - { - memcpy(&frame[0], pixelData_ + index * frameSize_, frameSize_); - } - } - }; - - - class DicomFrameIndex::PsmctRle1Index : public DicomFrameIndex::IIndex - { - private: - std::string pixelData_; - size_t frameSize_; - - public: - PsmctRle1Index(DcmDataset& dataset, - unsigned int countFrames, - size_t frameSize) : - frameSize_(frameSize) - { - if (!DicomImageDecoder::DecodePsmctRle1(pixelData_, dataset) || - pixelData_.size() < frameSize * countFrames) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - virtual void GetRawFrame(std::string& frame, - unsigned int index) const - { - frame.resize(frameSize_); - if (frameSize_ > 0) - { - memcpy(&frame[0], reinterpret_cast(&pixelData_[0]) + index * frameSize_, frameSize_); - } - } - }; - - - unsigned int DicomFrameIndex::GetFramesCount(DcmDataset& dicom) - { - const char* tmp = NULL; - if (!dicom.findAndGetString(DCM_NumberOfFrames, tmp).good() || - tmp == NULL) - { - return 1; - } - - int count = -1; - try - { - count = boost::lexical_cast(tmp); - } - catch (boost::bad_lexical_cast&) - { - } - - if (count < 0) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - return static_cast(count); - } - } - - - DicomFrameIndex::DicomFrameIndex(DcmDataset& dicom) - { - countFrames_ = GetFramesCount(dicom); - if (countFrames_ == 0) - { - // The image has no frame. No index is to be built. - return; - } - - // Test whether this image is composed of a sequence of fragments - DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dicom); - if (pixelSequence != NULL) - { - index_.reset(new FragmentIndex(pixelSequence, countFrames_)); - return; - } - - // Extract information about the image structure - DicomMap tags; - FromDcmtkBridge::ExtractDicomSummary(tags, dicom); - - DicomImageInformation information(tags); - - // Access to the raw pixel data - if (DicomImageDecoder::IsPsmctRle1(dicom)) - { - index_.reset(new PsmctRle1Index(dicom, countFrames_, information.GetFrameSize())); - } - else - { - index_.reset(new UncompressedIndex(dicom, countFrames_, information.GetFrameSize())); - } - } - - - void DicomFrameIndex::GetRawFrame(std::string& frame, - unsigned int index) const - { - if (index >= countFrames_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else if (index_.get() != NULL) - { - return index_->GetRawFrame(frame, index); - } - else - { - frame.clear(); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomFrameIndex.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Compatibility.h" -#include "../../Enumerations.h" - -#include -#include -#include -#include -#include -#include - -namespace Orthanc -{ - class DicomFrameIndex - { - private: - class IIndex : public boost::noncopyable - { - public: - virtual ~IIndex() - { - } - - virtual void GetRawFrame(std::string& frame, - unsigned int index) const = 0; - }; - - class FragmentIndex; - class UncompressedIndex; - class PsmctRle1Index; - - std::unique_ptr index_; - unsigned int countFrames_; - - public: - DicomFrameIndex(DcmDataset& dicom); - - unsigned int GetFramesCount() const - { - return countFrames_; - } - - void GetRawFrame(std::string& frame, - unsigned int index) const; - - static unsigned int GetFramesCount(DcmDataset& dicom); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1042 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeaders.h" -#include "DicomImageDecoder.h" - -#include "../ParsedDicomFile.h" - - -/*========================================================================= - - This file is based on portions of the following project - (cf. function "DecodePsmctRle1()"): - - Program: GDCM (Grassroots DICOM). A DICOM library - Module: http://gdcm.sourceforge.net/Copyright.html - - Copyright (c) 2006-2011 Mathieu Malaterre - Copyright (c) 1993-2005 CREATIS - (CREATIS = Centre de Recherche et d'Applications en Traitement de l'Image) - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any - contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to - endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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. - - =========================================================================*/ - - -#include "../../Logging.h" -#include "../../OrthancException.h" -#include "../../Images/Image.h" -#include "../../Images/ImageProcessing.h" -#include "../../DicomFormat/DicomIntegerPixelAccessor.h" -#include "../ToDcmtkBridge.h" -#include "../FromDcmtkBridge.h" - -#if ORTHANC_ENABLE_PNG == 1 -# include "../../Images/PngWriter.h" -#endif - -#if ORTHANC_ENABLE_JPEG == 1 -# include "../../Images/JpegWriter.h" -#endif -#include "../../Images/PamWriter.h" - -#include - -#include -#include -#include -#include - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 -# include -# include -# include -# include -#endif - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - -#if DCMTK_VERSION_NUMBER <= 360 -# define EXS_JPEGProcess1 EXS_JPEGProcess1TransferSyntax -# define EXS_JPEGProcess2_4 EXS_JPEGProcess2_4TransferSyntax -# define EXS_JPEGProcess6_8 EXS_JPEGProcess6_8TransferSyntax -# define EXS_JPEGProcess10_12 EXS_JPEGProcess10_12TransferSyntax -# define EXS_JPEGProcess14 EXS_JPEGProcess14TransferSyntax -# define EXS_JPEGProcess14SV1 EXS_JPEGProcess14SV1TransferSyntax -#endif - -namespace Orthanc -{ - static const DicomTag DICOM_TAG_CONTENT(0x07a1, 0x100a); - static const DicomTag DICOM_TAG_COMPRESSION_TYPE(0x07a1, 0x1011); - - - bool DicomImageDecoder::IsPsmctRle1(DcmDataset& dataset) - { - DcmElement* e; - char* c; - - // Check whether the DICOM instance contains an image encoded with - // the PMSCT_RLE1 scheme. - if (!dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_COMPRESSION_TYPE), e).good() || - e == NULL || - !e->isaString() || - !e->getString(c).good() || - c == NULL || - strcmp("PMSCT_RLE1", c)) - { - return false; - } - else - { - return true; - } - } - - - bool DicomImageDecoder::DecodePsmctRle1(std::string& output, - DcmDataset& dataset) - { - // Check whether the DICOM instance contains an image encoded with - // the PMSCT_RLE1 scheme. - if (!IsPsmctRle1(dataset)) - { - return false; - } - - // OK, this is a custom RLE encoding from Philips. Get the pixel - // data from the appropriate private DICOM tag. - Uint8* pixData = NULL; - DcmElement* e; - if (!dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_CONTENT), e).good() || - e == NULL || - e->getUint8Array(pixData) != EC_Normal) - { - return false; - } - - // The "unsigned" below IS VERY IMPORTANT - const uint8_t* inbuffer = reinterpret_cast(pixData); - const size_t length = e->getLength(); - - /** - * The code below is an adaptation of a sample code for GDCM by - * Mathieu Malaterre (under a BSD license). - * http://gdcm.sourceforge.net/html/rle2img_8cxx-example.html - **/ - - // RLE pass - std::vector temp; - temp.reserve(length); - for (size_t i = 0; i < length; i++) - { - if (inbuffer[i] == 0xa5) - { - temp.push_back(inbuffer[i+2]); - for (uint8_t repeat = inbuffer[i + 1]; repeat != 0; repeat--) - { - temp.push_back(inbuffer[i+2]); - } - i += 2; - } - else - { - temp.push_back(inbuffer[i]); - } - } - - // Delta encoding pass - uint16_t delta = 0; - output.clear(); - output.reserve(temp.size()); - for (size_t i = 0; i < temp.size(); i++) - { - uint16_t value; - - if (temp[i] == 0x5a) - { - uint16_t v1 = temp[i + 1]; - uint16_t v2 = temp[i + 2]; - value = (v2 << 8) + v1; - i += 2; - } - else - { - value = delta + (int8_t) temp[i]; - } - - output.push_back(value & 0xff); - output.push_back(value >> 8); - delta = value; - } - - if (output.size() % 2) - { - output.resize(output.size() - 1); - } - - return true; - } - - - class DicomImageDecoder::ImageSource - { - private: - std::string psmct_; - std::unique_ptr slowAccessor_; - - public: - void Setup(DcmDataset& dataset, - unsigned int frame) - { - psmct_.clear(); - slowAccessor_.reset(NULL); - - // See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data - - DicomMap m; - FromDcmtkBridge::ExtractDicomSummary(m, dataset); - - /** - * Create an accessor to the raw values of the DICOM image. - **/ - - DcmElement* e; - if (dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_DATA), e).good() && - e != NULL) - { - Uint8* pixData = NULL; - if (e->getUint8Array(pixData) == EC_Normal) - { - slowAccessor_.reset(new DicomIntegerPixelAccessor(m, pixData, e->getLength())); - } - } - else if (DecodePsmctRle1(psmct_, dataset)) - { - LOG(INFO) << "The PMSCT_RLE1 decoding has succeeded"; - Uint8* pixData = NULL; - if (psmct_.size() > 0) - { - pixData = reinterpret_cast(&psmct_[0]); - } - - slowAccessor_.reset(new DicomIntegerPixelAccessor(m, pixData, psmct_.size())); - } - - if (slowAccessor_.get() == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - slowAccessor_->SetCurrentFrame(frame); - } - - unsigned int GetWidth() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetInformation().GetWidth(); - } - - unsigned int GetHeight() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetInformation().GetHeight(); - } - - unsigned int GetChannelCount() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetInformation().GetChannelCount(); - } - - const DicomIntegerPixelAccessor& GetAccessor() const - { - assert(slowAccessor_.get() != NULL); - return *slowAccessor_; - } - - unsigned int GetSize() const - { - assert(slowAccessor_.get() != NULL); - return slowAccessor_->GetSize(); - } - }; - - - ImageAccessor* DicomImageDecoder::CreateImage(DcmDataset& dataset, - bool ignorePhotometricInterpretation) - { - DicomMap m; - FromDcmtkBridge::ExtractDicomSummary(m, dataset); - - DicomImageInformation info(m); - PixelFormat format; - - if (!info.ExtractPixelFormat(format, ignorePhotometricInterpretation)) - { - LOG(WARNING) << "Unsupported DICOM image: " << info.GetBitsStored() - << "bpp, " << info.GetChannelCount() << " channels, " - << (info.IsSigned() ? "signed" : "unsigned") - << (info.IsPlanar() ? ", planar, " : ", non-planar, ") - << EnumerationToString(info.GetPhotometricInterpretation()) - << " photometric interpretation"; - throw OrthancException(ErrorCode_NotImplemented); - } - - return new Image(format, info.GetWidth(), info.GetHeight(), false); - } - - - template - static void CopyPixels(ImageAccessor& target, - const DicomIntegerPixelAccessor& source) - { - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - const PixelType minValue = std::numeric_limits::min(); - const PixelType maxValue = std::numeric_limits::max(); - - for (unsigned int y = 0; y < source.GetInformation().GetHeight(); y++) - { - PixelType* pixel = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < source.GetInformation().GetWidth(); x++) - { - for (unsigned int c = 0; c < source.GetInformation().GetChannelCount(); c++, pixel++) - { - int32_t v = source.GetValue(x, y, c); - if (v < static_cast(minValue)) - { - *pixel = minValue; - } - else if (v > static_cast(maxValue)) - { - *pixel = maxValue; - } - else - { - *pixel = static_cast(v); - } - } - } - } - } - - - static ImageAccessor* DecodeLookupTable(std::unique_ptr& target, - const DicomImageInformation& info, - DcmDataset& dataset, - const uint8_t* pixelData, - unsigned long pixelLength) - { - LOG(INFO) << "Decoding a lookup table"; - - OFString r, g, b; - PixelFormat format; - const uint16_t* lutRed = NULL; - const uint16_t* lutGreen = NULL; - const uint16_t* lutBlue = NULL; - unsigned long rc = 0; - unsigned long gc = 0; - unsigned long bc = 0; - - if (pixelData == NULL && - !dataset.findAndGetUint8Array(DCM_PixelData, pixelData, &pixelLength).good()) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - if (info.IsPlanar() || - info.GetNumberOfFrames() != 1 || - !info.ExtractPixelFormat(format, false) || - !dataset.findAndGetOFStringArray(DCM_BluePaletteColorLookupTableDescriptor, b).good() || - !dataset.findAndGetOFStringArray(DCM_GreenPaletteColorLookupTableDescriptor, g).good() || - !dataset.findAndGetOFStringArray(DCM_RedPaletteColorLookupTableDescriptor, r).good() || - !dataset.findAndGetUint16Array(DCM_BluePaletteColorLookupTableData, lutBlue, &bc).good() || - !dataset.findAndGetUint16Array(DCM_GreenPaletteColorLookupTableData, lutGreen, &gc).good() || - !dataset.findAndGetUint16Array(DCM_RedPaletteColorLookupTableData, lutRed, &rc).good() || - r != g || - r != b || - g != b || - lutRed == NULL || - lutGreen == NULL || - lutBlue == NULL || - pixelData == NULL) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - switch (format) - { - case PixelFormat_RGB24: - { - if (r != "256\\0\\16" || - rc != 256 || - gc != 256 || - bc != 256 || - pixelLength != target->GetWidth() * target->GetHeight()) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - const uint8_t* source = reinterpret_cast(pixelData); - - for (unsigned int y = 0; y < target->GetHeight(); y++) - { - uint8_t* p = reinterpret_cast(target->GetRow(y)); - - for (unsigned int x = 0; x < target->GetWidth(); x++) - { - p[0] = lutRed[*source] >> 8; - p[1] = lutGreen[*source] >> 8; - p[2] = lutBlue[*source] >> 8; - source++; - p += 3; - } - } - - return target.release(); - } - - case PixelFormat_RGB48: - { - if (r != "0\\0\\16" || - rc != 65536 || - gc != 65536 || - bc != 65536 || - pixelLength != 2 * target->GetWidth() * target->GetHeight()) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - const uint16_t* source = reinterpret_cast(pixelData); - - for (unsigned int y = 0; y < target->GetHeight(); y++) - { - uint16_t* p = reinterpret_cast(target->GetRow(y)); - - for (unsigned int x = 0; x < target->GetWidth(); x++) - { - p[0] = lutRed[*source]; - p[1] = lutGreen[*source]; - p[2] = lutBlue[*source]; - source++; - p += 3; - } - } - - return target.release(); - } - - default: - break; - } - - throw OrthancException(ErrorCode_InternalError); - } - - - ImageAccessor* DicomImageDecoder::DecodeUncompressedImage(DcmDataset& dataset, - unsigned int frame) - { - /** - * Create the target image. - **/ - - std::unique_ptr target(CreateImage(dataset, false)); - - ImageSource source; - source.Setup(dataset, frame); - - if (source.GetWidth() != target->GetWidth() || - source.GetHeight() != target->GetHeight()) - { - throw OrthancException(ErrorCode_InternalError); - } - - - /** - * Deal with lookup tables - **/ - - const DicomImageInformation& info = source.GetAccessor().GetInformation(); - - if (info.GetPhotometricInterpretation() == PhotometricInterpretation_Palette) - { - return DecodeLookupTable(target, info, dataset, NULL, 0); - } - - - /** - * If the format of the DICOM buffer is natively supported, use a - * direct access to copy its values. - **/ - - bool fastVersionSuccess = false; - PixelFormat sourceFormat; - if (!info.IsPlanar() && - info.ExtractPixelFormat(sourceFormat, false)) - { - try - { - size_t frameSize = info.GetHeight() * info.GetWidth() * GetBytesPerPixel(sourceFormat); - if ((frame + 1) * frameSize <= source.GetSize()) - { - const uint8_t* buffer = reinterpret_cast(source.GetAccessor().GetPixelData()); - - ImageAccessor sourceImage; - sourceImage.AssignReadOnly(sourceFormat, - info.GetWidth(), - info.GetHeight(), - info.GetWidth() * GetBytesPerPixel(sourceFormat), - buffer + frame * frameSize); - - ImageProcessing::Convert(*target, sourceImage); - ImageProcessing::ShiftRight(*target, info.GetShift()); - fastVersionSuccess = true; - } - } - catch (OrthancException&) - { - // Unsupported conversion, use the slow version - } - } - - /** - * Slow version : loop over the DICOM buffer, storing its value - * into the target image. - **/ - - if (!fastVersionSuccess) - { - switch (target->GetFormat()) - { - case PixelFormat_RGB24: - case PixelFormat_RGBA32: - case PixelFormat_Grayscale8: - CopyPixels(*target, source.GetAccessor()); - break; - - case PixelFormat_Grayscale16: - CopyPixels(*target, source.GetAccessor()); - break; - - case PixelFormat_SignedGrayscale16: - CopyPixels(*target, source.GetAccessor()); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - return target.release(); - } - - - ImageAccessor* DicomImageDecoder::ApplyCodec - (const DcmCodec& codec, - const DcmCodecParameter& parameters, - const DcmRepresentationParameter& representationParameter, - DcmDataset& dataset, - unsigned int frame) - { - DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset); - if (pixelSequence == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - DicomMap m; - FromDcmtkBridge::ExtractDicomSummary(m, dataset); - DicomImageInformation info(m); - - std::unique_ptr target(CreateImage(dataset, true)); - - Uint32 startFragment = 0; // Default - OFString decompressedColorModel; // Out - - OFCondition c; - - if (info.GetPhotometricInterpretation() == PhotometricInterpretation_Palette && - info.GetChannelCount() == 1) - { - std::string uncompressed; - uncompressed.resize(info.GetWidth() * info.GetHeight() * info.GetBytesPerValue()); - - if (uncompressed.size() == 0 || - !codec.decodeFrame(&representationParameter, - pixelSequence, ¶meters, - &dataset, frame, startFragment, &uncompressed[0], - uncompressed.size(), decompressedColorModel).good()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot decode a palette image"); - } - - return DecodeLookupTable(target, info, dataset, - reinterpret_cast(uncompressed.c_str()), - uncompressed.size()); - } - else - { - if (!codec.decodeFrame(&representationParameter, - pixelSequence, ¶meters, - &dataset, frame, startFragment, target->GetBuffer(), - target->GetSize(), decompressedColorModel).good()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot decode a non-palette image"); - } - - return target.release(); - } - } - - - ImageAccessor* DicomImageDecoder::Decode(ParsedDicomFile& dicom, - unsigned int frame) - { - if (dicom.GetDcmtkObject().getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - return Decode(*dicom.GetDcmtkObject().getDataset(), frame); - } - } - - - ImageAccessor* DicomImageDecoder::Decode(DcmDataset& dataset, - unsigned int frame) - { - E_TransferSyntax syntax = dataset.getCurrentXfer(); - - /** - * Deal with uncompressed, raw images. - * http://support.dcmtk.org/docs/dcxfer_8h-source.html - **/ - if (syntax == EXS_Unknown || - syntax == EXS_LittleEndianImplicit || - syntax == EXS_BigEndianImplicit || - syntax == EXS_LittleEndianExplicit || - syntax == EXS_BigEndianExplicit) - { - return DecodeUncompressedImage(dataset, frame); - } - - -#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 - /** - * Deal with JPEG-LS images. - **/ - - if (syntax == EXS_JPEGLSLossless || - syntax == EXS_JPEGLSLossy) - { - // The (2, OFTrue) are the default parameters as found in DCMTK 3.6.2 - // http://support.dcmtk.org/docs/classDJLSRepresentationParameter.html - DJLSRepresentationParameter representationParameter(2, OFTrue); - - DJLSCodecParameter parameters; - std::unique_ptr decoder; - - switch (syntax) - { - case EXS_JPEGLSLossless: - LOG(INFO) << "Decoding a JPEG-LS lossless DICOM image"; - decoder.reset(new DJLSLosslessDecoder); - break; - - case EXS_JPEGLSLossy: - LOG(INFO) << "Decoding a JPEG-LS near-lossless DICOM image"; - decoder.reset(new DJLSNearLosslessDecoder); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - return ApplyCodec(*decoder, parameters, representationParameter, dataset, frame); - } -#endif - - -#if ORTHANC_ENABLE_DCMTK_JPEG == 1 - /** - * Deal with JPEG images. - **/ - - if (syntax == EXS_JPEGProcess1 || // DJDecoderBaseline - syntax == EXS_JPEGProcess2_4 || // DJDecoderExtended - syntax == EXS_JPEGProcess6_8 || // DJDecoderSpectralSelection (retired) - syntax == EXS_JPEGProcess10_12 || // DJDecoderProgressive (retired) - syntax == EXS_JPEGProcess14 || // DJDecoderLossless - syntax == EXS_JPEGProcess14SV1) // DJDecoderP14SV1 - { - // http://support.dcmtk.org/docs-snapshot/djutils_8h.html#a2a9695e5b6b0f5c45a64c7f072c1eb9d - DJCodecParameter parameters( - ECC_lossyYCbCr, // Mode for color conversion for compression, Unused for decompression - EDC_photometricInterpretation, // Perform color space conversion from YCbCr to RGB if DICOM photometric interpretation indicates YCbCr - EUC_default, // Mode for UID creation, unused for decompression - EPC_default); // Automatically determine whether color-by-plane is required from the SOP Class UID and decompressed photometric interpretation - DJ_RPLossy representationParameter; - std::unique_ptr decoder; - - switch (syntax) - { - case EXS_JPEGProcess1: - LOG(INFO) << "Decoding a JPEG baseline (process 1) DICOM image"; - decoder.reset(new DJDecoderBaseline); - break; - - case EXS_JPEGProcess2_4 : - LOG(INFO) << "Decoding a JPEG baseline (processes 2 and 4) DICOM image"; - decoder.reset(new DJDecoderExtended); - break; - - case EXS_JPEGProcess6_8: // Retired - LOG(INFO) << "Decoding a JPEG spectral section, nonhierarchical (processes 6 and 8) DICOM image"; - decoder.reset(new DJDecoderSpectralSelection); - break; - - case EXS_JPEGProcess10_12: // Retired - LOG(INFO) << "Decoding a JPEG full progression, nonhierarchical (processes 10 and 12) DICOM image"; - decoder.reset(new DJDecoderProgressive); - break; - - case EXS_JPEGProcess14: - LOG(INFO) << "Decoding a JPEG lossless, nonhierarchical (process 14) DICOM image"; - decoder.reset(new DJDecoderLossless); - break; - - case EXS_JPEGProcess14SV1: - LOG(INFO) << "Decoding a JPEG lossless, nonhierarchical, first-order prediction (process 14 selection value 1) DICOM image"; - decoder.reset(new DJDecoderP14SV1); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - return ApplyCodec(*decoder, parameters, representationParameter, dataset, frame); - } -#endif - - - if (syntax == EXS_RLELossless) - { - LOG(INFO) << "Decoding a RLE lossless DICOM image"; - DcmRLECodecParameter parameters; - DcmRLECodecDecoder decoder; - DcmRLERepresentationParameter representationParameter; - return ApplyCodec(decoder, parameters, representationParameter, dataset, frame); - } - - - /** - * This DICOM image format is not natively supported by - * Orthanc. As a last resort, try and decode it through DCMTK by - * converting its transfer syntax to Little Endian. This will - * result in higher memory consumption. This is actually the - * second example of the following page: - * http://support.dcmtk.org/docs/mod_dcmjpeg.html#Examples - **/ - - { - LOG(INFO) << "Trying to decode a compressed image by transcoding it to Little Endian Explicit"; - - std::unique_ptr converted(dynamic_cast(dataset.clone())); - converted->chooseRepresentation(EXS_LittleEndianExplicit, NULL); - - if (converted->canWriteXfer(EXS_LittleEndianExplicit)) - { - return DecodeUncompressedImage(*converted, frame); - } - } - - DicomTransferSyntax s; - if (FromDcmtkBridge::LookupOrthancTransferSyntax(s, dataset.getCurrentXfer())) - { - throw OrthancException(ErrorCode_NotImplemented, - "The built-in DCMTK decoder cannot decode some DICOM instance " - "whose transfer syntax is: " + std::string(GetTransferSyntaxUid(s))); - } - else - { - throw OrthancException(ErrorCode_NotImplemented, - "The built-in DCMTK decoder cannot decode some DICOM instance"); - } - } - - - static bool IsColorImage(PixelFormat format) - { - return (format == PixelFormat_RGB24 || - format == PixelFormat_RGBA32); - } - - - bool DicomImageDecoder::TruncateDecodedImage(std::unique_ptr& image, - PixelFormat format, - bool allowColorConversion) - { - // If specified, prevent the conversion between color and - // grayscale images - bool isSourceColor = IsColorImage(image->GetFormat()); - bool isTargetColor = IsColorImage(format); - - if (!allowColorConversion) - { - if (isSourceColor ^ isTargetColor) - { - return false; - } - } - - if (image->GetFormat() != format) - { - // A conversion is required - std::unique_ptr target - (new Image(format, image->GetWidth(), image->GetHeight(), false)); - ImageProcessing::Convert(*target, *image); - -#if __cplusplus < 201103L - image.reset(target.release()); -#else - image = std::move(target); -#endif - } - - return true; - } - - - bool DicomImageDecoder::PreviewDecodedImage(std::unique_ptr& image) - { - switch (image->GetFormat()) - { - case PixelFormat_RGB24: - { - // Directly return color images without modification (RGB) - return true; - } - - case PixelFormat_RGB48: - { - std::unique_ptr target - (new Image(PixelFormat_RGB24, image->GetWidth(), image->GetHeight(), false)); - ImageProcessing::Convert(*target, *image); - -#if __cplusplus < 201103L - image.reset(target.release()); -#else - image = std::move(target); -#endif - - return true; - } - - case PixelFormat_Grayscale8: - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - { - // Grayscale image: Stretch its dynamics to the [0,255] range - int64_t a, b; - ImageProcessing::GetMinMaxIntegerValue(a, b, *image); - - if (a == b) - { - ImageProcessing::Set(*image, 0); - } - else - { - ImageProcessing::ShiftScale(*image, static_cast(-a), - 255.0f / static_cast(b - a), - true /* TODO - Consider using "false" to speed up */); - } - - // If the source image is not grayscale 8bpp, convert it - if (image->GetFormat() != PixelFormat_Grayscale8) - { - std::unique_ptr target - (new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight(), false)); - ImageProcessing::Convert(*target, *image); - -#if __cplusplus < 201103L - image.reset(target.release()); -#else - image = std::move(target); -#endif - } - - return true; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void DicomImageDecoder::ApplyExtractionMode(std::unique_ptr& image, - ImageExtractionMode mode, - bool invert) - { - if (image.get() == NULL) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - bool ok = false; - - switch (mode) - { - case ImageExtractionMode_UInt8: - ok = TruncateDecodedImage(image, PixelFormat_Grayscale8, false); - break; - - case ImageExtractionMode_UInt16: - ok = TruncateDecodedImage(image, PixelFormat_Grayscale16, false); - break; - - case ImageExtractionMode_Int16: - ok = TruncateDecodedImage(image, PixelFormat_SignedGrayscale16, false); - break; - - case ImageExtractionMode_Preview: - ok = PreviewDecodedImage(image); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (ok) - { - assert(image.get() != NULL); - - if (invert) - { - Orthanc::ImageProcessing::Invert(*image); - } - } - else - { - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void DicomImageDecoder::ExtractPamImage(std::string& result, - std::unique_ptr& image, - ImageExtractionMode mode, - bool invert) - { - ApplyExtractionMode(image, mode, invert); - - PamWriter writer; - writer.WriteToMemory(result, *image); - } - -#if ORTHANC_ENABLE_PNG == 1 - void DicomImageDecoder::ExtractPngImage(std::string& result, - std::unique_ptr& image, - ImageExtractionMode mode, - bool invert) - { - ApplyExtractionMode(image, mode, invert); - - PngWriter writer; - writer.WriteToMemory(result, *image); - } -#endif - - -#if ORTHANC_ENABLE_JPEG == 1 - void DicomImageDecoder::ExtractJpegImage(std::string& result, - std::unique_ptr& image, - ImageExtractionMode mode, - bool invert, - uint8_t quality) - { - if (mode != ImageExtractionMode_UInt8 && - mode != ImageExtractionMode_Preview) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - ApplyExtractionMode(image, mode, invert); - - JpegWriter writer; - writer.SetQuality(quality); - writer.WriteToMemory(result, *image); - } -#endif -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/Internals/DicomImageDecoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,130 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Compatibility.h" -#include "../../Images/ImageAccessor.h" - -#include - -#if !defined(ORTHANC_ENABLE_JPEG) -# error The macro ORTHANC_ENABLE_JPEG must be defined -#endif - -#if !defined(ORTHANC_ENABLE_PNG) -# error The macro ORTHANC_ENABLE_PNG must be defined -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG) -# error The macro ORTHANC_ENABLE_DCMTK_JPEG must be defined -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) -# error The macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined -#endif - - -class DcmDataset; -class DcmCodec; -class DcmCodecParameter; -class DcmRepresentationParameter; - -namespace Orthanc -{ - class ParsedDicomFile; - - class DicomImageDecoder : public boost::noncopyable - { - private: - class ImageSource; - - DicomImageDecoder() // This is a fully abstract class, no constructor - { - } - - static ImageAccessor* CreateImage(DcmDataset& dataset, - bool ignorePhotometricInterpretation); - - static ImageAccessor* DecodeUncompressedImage(DcmDataset& dataset, - unsigned int frame); - - static ImageAccessor* ApplyCodec(const DcmCodec& codec, - const DcmCodecParameter& parameters, - const DcmRepresentationParameter& representationParameter, - DcmDataset& dataset, - unsigned int frame); - - static bool TruncateDecodedImage(std::unique_ptr& image, - PixelFormat format, - bool allowColorConversion); - - static bool PreviewDecodedImage(std::unique_ptr& image); - - static void ApplyExtractionMode(std::unique_ptr& image, - ImageExtractionMode mode, - bool invert); - - public: - static bool IsPsmctRle1(DcmDataset& dataset); - - static bool DecodePsmctRle1(std::string& output, - DcmDataset& dataset); - - static ImageAccessor *Decode(ParsedDicomFile& dicom, - unsigned int frame); - - static ImageAccessor *Decode(DcmDataset& dataset, - unsigned int frame); - - static void ExtractPamImage(std::string& result, - std::unique_ptr& image, - ImageExtractionMode mode, - bool invert); - -#if ORTHANC_ENABLE_PNG == 1 - static void ExtractPngImage(std::string& result, - std::unique_ptr& image, - ImageExtractionMode mode, - bool invert); -#endif - -#if ORTHANC_ENABLE_JPEG == 1 - static void ExtractJpegImage(std::string& result, - std::unique_ptr& image, - ImageExtractionMode mode, - bool invert, - uint8_t quality); -#endif - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ITagVisitor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ITagVisitor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ITagVisitor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ITagVisitor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,103 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../DicomFormat/DicomTag.h" - -#include -#include - -namespace Orthanc -{ - class ITagVisitor : public boost::noncopyable - { - public: - enum Action - { - Action_Replace, - Action_None - }; - - virtual ~ITagVisitor() - { - } - - // Visiting a DICOM element that is internal to DCMTK - virtual void VisitNotSupported(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr) = 0; - - // SQ - virtual void VisitEmptySequence(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag) = 0; - - // SL, SS, UL, US - virtual void VisitIntegers(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) = 0; - - // FL, FD, OD, OF - virtual void VisitDoubles(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::vector& values) = 0; - - // AT - virtual void VisitAttributes(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - const std::vector& values) = 0; - - // OB, OL, OW, UN - virtual void VisitBinary(const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const void* data, - size_t size) = 0; - - // Visiting an UTF-8 string - virtual Action VisitString(std::string& newValue, - const std::vector& parentTags, - const std::vector& parentIndexes, - const DicomTag& tag, - ValueRepresentation vr, - const std::string& value) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,109 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "MemoryBufferTranscoder.h" - -#include "../OrthancException.h" -#include "FromDcmtkBridge.h" - -#if !defined(NDEBUG) // For debugging -# include "ParsedDicomFile.h" -#endif - -namespace Orthanc -{ - static void CheckTargetSyntax(const std::string& transcoded, - const std::set& allowedSyntaxes) - { -#if !defined(NDEBUG) - // Debug mode - ParsedDicomFile parsed(transcoded); - - std::string s; - DicomTransferSyntax a, b; - if (!parsed.LookupTransferSyntax(s) || - !FromDcmtkBridge::LookupOrthancTransferSyntax(a, parsed.GetDcmtkObject()) || - !LookupTransferSyntax(b, s) || - a != b || - allowedSyntaxes.find(a) == allowedSyntaxes.end()) - { - throw OrthancException( - ErrorCode_Plugin, - "DEBUG - The transcoding plugin has not written to one of the allowed transfer syntaxes"); - } -#endif - } - - - bool MemoryBufferTranscoder::Transcode(DicomImage& target, - DicomImage& source, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - target.Clear(); - -#if !defined(NDEBUG) - // Don't run this code in release mode, as it implies parsing the DICOM file - DicomTransferSyntax sourceSyntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(sourceSyntax, source.GetParsed())) - { - LOG(ERROR) << "Unsupport transfer syntax for transcoding"; - return false; - } - - const std::string sourceSopInstanceUid = GetSopInstanceUid(source.GetParsed()); -#endif - - std::string buffer; - if (TranscodeBuffer(buffer, source.GetBufferData(), source.GetBufferSize(), - allowedSyntaxes, allowNewSopInstanceUid)) - { - CheckTargetSyntax(buffer, allowedSyntaxes); // For debug only - - target.AcquireBuffer(buffer); - -#if !defined(NDEBUG) - // Only run the sanity check in debug mode - CheckTranscoding(target, sourceSyntax, sourceSopInstanceUid, - allowedSyntaxes, allowNewSopInstanceUid); -#endif - - return true; - } - else - { - return false; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/MemoryBufferTranscoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IDicomTranscoder.h" - -namespace Orthanc -{ - // This is the basis class for transcoding plugins - class MemoryBufferTranscoder : public IDicomTranscoder - { - protected: - virtual bool TranscodeBuffer(std::string& target, - const void* buffer, - size_t size, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) = 0; - - public: - virtual bool Transcode(DicomImage& target /* out */, - DicomImage& source, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,195 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ParsedDicomDir.h" - -#include "../Compatibility.h" -#include "../OrthancException.h" -#include "ParsedDicomFile.h" -#include "FromDcmtkBridge.h" - -#include - - -namespace Orthanc -{ - void ParsedDicomDir::Clear() - { - for (size_t i = 0; i < content_.size(); i++) - { - assert(content_[i] != NULL); - delete content_[i]; - } - } - - - bool ParsedDicomDir::LookupIndexOfOffset(size_t& target, - unsigned int offset) const - { - if (offset == 0) - { - return false; - } - - OffsetToIndex::const_iterator found = offsetToIndex_.find(offset); - if (found == offsetToIndex_.end()) - { - // Error in the algorithm that computes the offsets - throw OrthancException(ErrorCode_InternalError); - } - else - { - target = found->second; - return true; - } - } - - - ParsedDicomDir::ParsedDicomDir(const std::string content) - { - ParsedDicomFile dicom(content); - - DcmSequenceOfItems* sequence = NULL; - if (dicom.GetDcmtkObject().getDataset() == NULL || - !dicom.GetDcmtkObject().getDataset()->findAndGetSequence(DCM_DirectoryRecordSequence, sequence).good() || - sequence == NULL) - { - throw OrthancException(ErrorCode_BadFileFormat, "Not a DICOMDIR"); - } - - content_.resize(sequence->card()); - nextOffsets_.resize(content_.size()); - lowerOffsets_.resize(content_.size()); - - // Manually reconstruct the list of all the available offsets of - // "DcmItem", as "fStartPosition" is a protected member in DCMTK - // API - std::set availableOffsets; - availableOffsets.insert(0); - - - for (unsigned long i = 0; i < sequence->card(); i++) - { - DcmItem* item = sequence->getItem(i); - if (item == NULL) - { - Clear(); - throw OrthancException(ErrorCode_InternalError); - } - - Uint32 next, lower; - if (!item->findAndGetUint32(DCM_OffsetOfTheNextDirectoryRecord, next).good() || - !item->findAndGetUint32(DCM_OffsetOfReferencedLowerLevelDirectoryEntity, lower).good()) - { - item->writeXML(std::cout); - throw OrthancException(ErrorCode_BadFileFormat, - "Missing offsets in DICOMDIR"); - } - - nextOffsets_[i] = next; - lowerOffsets_[i] = lower; - - std::unique_ptr entry(new DicomMap); - FromDcmtkBridge::ExtractDicomSummary(*entry, *item); - - if (next != 0) - { - availableOffsets.insert(next); - } - - if (lower != 0) - { - availableOffsets.insert(lower); - } - - content_[i] = entry.release(); - } - - if (content_.size() != availableOffsets.size()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Inconsistent offsets in DICOMDIR"); - } - - unsigned int index = 0; - for (std::set::const_iterator it = availableOffsets.begin(); - it != availableOffsets.end(); ++it) - { - offsetToIndex_[*it] = index; - index ++; - } - } - - - const DicomMap& ParsedDicomDir::GetItem(size_t i) const - { - if (i >= content_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - assert(content_[i] != NULL); - return *content_[i]; - } - } - - - bool ParsedDicomDir::LookupNext(size_t& target, - size_t index) const - { - if (index >= nextOffsets_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return LookupIndexOfOffset(target, nextOffsets_[index]); - } - } - - - bool ParsedDicomDir::LookupLower(size_t& target, - size_t index) const - { - if (index >= lowerOffsets_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return LookupIndexOfOffset(target, lowerOffsets_[index]); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomDir.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if ORTHANC_ENABLE_DCMTK != 1 -# error The macro ORTHANC_ENABLE_DCMTK must be set to 1 to use this file -#endif - -#include "../DicomFormat/DicomMap.h" - -namespace Orthanc -{ - class ParsedDicomDir : public boost::noncopyable - { - private: - typedef std::map OffsetToIndex; - - std::vector content_; - std::vector nextOffsets_; - std::vector lowerOffsets_; - OffsetToIndex offsetToIndex_; - - void Clear(); - - bool LookupIndexOfOffset(size_t& target, - unsigned int offset) const; - - public: - ParsedDicomDir(const std::string content); - - ~ParsedDicomDir() - { - Clear(); - } - - size_t GetSize() const - { - return content_.size(); - } - - const DicomMap& GetItem(size_t i) const; - - bool LookupNext(size_t& target, - size_t index) const; - - bool LookupLower(size_t& target, - size_t index) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1716 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - - -/*========================================================================= - - This file is based on portions of the following project: - - Program: GDCM (Grassroots DICOM). A DICOM library - Module: http://gdcm.sourceforge.net/Copyright.html - - Copyright (c) 2006-2011 Mathieu Malaterre - Copyright (c) 1993-2005 CREATIS - (CREATIS = Centre de Recherche et d'Applications en Traitement de l'Image) - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any - contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to - endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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. - - =========================================================================*/ - - -#include "../PrecompiledHeaders.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "ParsedDicomFile.h" - -#include "FromDcmtkBridge.h" -#include "Internals/DicomFrameIndex.h" -#include "ToDcmtkBridge.h" - -#include "../Images/PamReader.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - -#if ORTHANC_ENABLE_JPEG == 1 -# include "../Images/JpegReader.h" -#endif - -#if ORTHANC_ENABLE_PNG == 1 -# include "../Images/PngReader.h" -#endif - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include - - -#if DCMTK_VERSION_NUMBER <= 360 -# define EXS_JPEGProcess1 EXS_JPEGProcess1TransferSyntax -#endif - - - -namespace Orthanc -{ - struct ParsedDicomFile::PImpl - { - std::unique_ptr file_; - std::unique_ptr frameIndex_; - }; - - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - static void ParseTagAndGroup(DcmTagKey& key, - const std::string& tag) - { - DicomTag t = FromDcmtkBridge::ParseTag(tag); - key = DcmTagKey(t.GetGroup(), t.GetElement()); - } - - - static unsigned int GetPixelDataBlockCount(DcmPixelData& pixelData, - E_TransferSyntax transferSyntax) - { - DcmPixelSequence* pixelSequence = NULL; - if (pixelData.getEncapsulatedRepresentation - (transferSyntax, NULL, pixelSequence).good() && pixelSequence) - { - return pixelSequence->card(); - } - else - { - return 1; - } - } - - - static void SendPathValueForDictionary(RestApiOutput& output, - DcmItem& dicom) - { - Json::Value v = Json::arrayValue; - - for (unsigned long i = 0; i < dicom.card(); i++) - { - DcmElement* element = dicom.getElement(i); - if (element) - { - char buf[16]; - sprintf(buf, "%04x-%04x", element->getTag().getGTag(), element->getTag().getETag()); - v.append(buf); - } - } - - output.AnswerJson(v); - } - - - static void SendSequence(RestApiOutput& output, - DcmSequenceOfItems& sequence) - { - // This element is a sequence - Json::Value v = Json::arrayValue; - - for (unsigned long i = 0; i < sequence.card(); i++) - { - v.append(boost::lexical_cast(i)); - } - - output.AnswerJson(v); - } - - - namespace - { - class DicomFieldStream : public IHttpStreamAnswer - { - private: - DcmElement& element_; - uint32_t length_; - uint32_t offset_; - std::string chunk_; - size_t chunkSize_; - - public: - DicomFieldStream(DcmElement& element, - E_TransferSyntax transferSyntax) : - element_(element), - length_(element.getLength(transferSyntax)), - offset_(0), - chunkSize_(0) - { - static const size_t CHUNK_SIZE = 64 * 1024; // Use chunks of max 64KB - chunk_.resize(CHUNK_SIZE); - } - - virtual HttpCompression SetupHttpCompression(bool /*gzipAllowed*/, - bool /*deflateAllowed*/) - ORTHANC_OVERRIDE - { - // No support for compression - return HttpCompression_None; - } - - virtual bool HasContentFilename(std::string& filename) ORTHANC_OVERRIDE - { - return false; - } - - virtual std::string GetContentType() ORTHANC_OVERRIDE - { - return EnumerationToString(MimeType_Binary); - } - - virtual uint64_t GetContentLength() ORTHANC_OVERRIDE - { - return length_; - } - - virtual bool ReadNextChunk() ORTHANC_OVERRIDE - { - assert(offset_ <= length_); - - if (offset_ == length_) - { - return false; - } - else - { - if (length_ - offset_ < chunk_.size()) - { - chunkSize_ = length_ - offset_; - } - else - { - chunkSize_ = chunk_.size(); - } - - OFCondition cond = element_.getPartialValue(&chunk_[0], offset_, chunkSize_); - - offset_ += chunkSize_; - - if (!cond.good()) - { - throw OrthancException(ErrorCode_InternalError, - "Error while sending a DICOM field: " + - std::string(cond.text())); - } - - return true; - } - } - - virtual const char *GetChunkContent() ORTHANC_OVERRIDE - { - return chunk_.c_str(); - } - - virtual size_t GetChunkSize() ORTHANC_OVERRIDE - { - return chunkSize_; - } - }; - } - - - static bool AnswerPixelData(RestApiOutput& output, - DcmItem& dicom, - E_TransferSyntax transferSyntax, - const std::string* blockUri) - { - DcmTag k(DICOM_TAG_PIXEL_DATA.GetGroup(), - DICOM_TAG_PIXEL_DATA.GetElement()); - - DcmElement *element = NULL; - if (!dicom.findAndGetElement(k, element).good() || - element == NULL) - { - return false; - } - - try - { - DcmPixelData& pixelData = dynamic_cast(*element); - if (blockUri == NULL) - { - // The user asks how many blocks are present in this pixel data - unsigned int blocks = GetPixelDataBlockCount(pixelData, transferSyntax); - - Json::Value result(Json::arrayValue); - for (unsigned int i = 0; i < blocks; i++) - { - result.append(boost::lexical_cast(i)); - } - - output.AnswerJson(result); - return true; - } - - - unsigned int block = boost::lexical_cast(*blockUri); - - if (block < GetPixelDataBlockCount(pixelData, transferSyntax)) - { - DcmPixelSequence* pixelSequence = NULL; - if (pixelData.getEncapsulatedRepresentation - (transferSyntax, NULL, pixelSequence).good() && pixelSequence) - { - // This is the case for JPEG transfer syntaxes - if (block < pixelSequence->card()) - { - DcmPixelItem* pixelItem = NULL; - if (pixelSequence->getItem(pixelItem, block).good() && pixelItem) - { - if (pixelItem->getLength() == 0) - { - output.AnswerBuffer(NULL, 0, MimeType_Binary); - return true; - } - - Uint8* buffer = NULL; - if (pixelItem->getUint8Array(buffer).good() && buffer) - { - output.AnswerBuffer(buffer, pixelItem->getLength(), MimeType_Binary); - return true; - } - } - } - } - else - { - // This is the case for raw, uncompressed image buffers - assert(*blockUri == "0"); - DicomFieldStream stream(*element, transferSyntax); - output.AnswerStream(stream); - } - } - } - catch (boost::bad_lexical_cast&) - { - // The URI entered by the user is not a number - } - catch (std::bad_cast&) - { - // This should never happen - } - - return false; - } - - - static void SendPathValueForLeaf(RestApiOutput& output, - const std::string& tag, - DcmItem& dicom, - E_TransferSyntax transferSyntax) - { - DcmTagKey k; - ParseTagAndGroup(k, tag); - - DcmSequenceOfItems* sequence = NULL; - if (dicom.findAndGetSequence(k, sequence).good() && - sequence != NULL && - sequence->getVR() == EVR_SQ) - { - SendSequence(output, *sequence); - return; - } - - DcmElement* element = NULL; - if (dicom.findAndGetElement(k, element).good() && - element != NULL && - //element->getVR() != EVR_UNKNOWN && // This would forbid private tags - element->getVR() != EVR_SQ) - { - DicomFieldStream stream(*element, transferSyntax); - output.AnswerStream(stream); - } - } -#endif - - - static inline uint16_t GetCharValue(char c) - { - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else - return 0; - } - - - static inline uint16_t GetTagValue(const char* c) - { - return ((GetCharValue(c[0]) << 12) + - (GetCharValue(c[1]) << 8) + - (GetCharValue(c[2]) << 4) + - GetCharValue(c[3])); - } - - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void ParsedDicomFile::SendPathValue(RestApiOutput& output, - const UriComponents& uri) - { - DcmItem* dicom = GetDcmtkObject().getDataset(); - E_TransferSyntax transferSyntax = GetDcmtkObject().getDataset()->getCurrentXfer(); - - // Special case: Accessing the pixel data - if (uri.size() == 1 || - uri.size() == 2) - { - DcmTagKey tag; - ParseTagAndGroup(tag, uri[0]); - - if (tag.getGroup() == DICOM_TAG_PIXEL_DATA.GetGroup() && - tag.getElement() == DICOM_TAG_PIXEL_DATA.GetElement()) - { - AnswerPixelData(output, *dicom, transferSyntax, uri.size() == 1 ? NULL : &uri[1]); - return; - } - } - - // Go down in the tag hierarchy according to the URI - for (size_t pos = 0; pos < uri.size() / 2; pos++) - { - size_t index; - try - { - index = boost::lexical_cast(uri[2 * pos + 1]); - } - catch (boost::bad_lexical_cast&) - { - return; - } - - DcmTagKey k; - DcmItem *child = NULL; - ParseTagAndGroup(k, uri[2 * pos]); - if (!dicom->findAndGetSequenceItem(k, child, index).good() || - child == NULL) - { - return; - } - - dicom = child; - } - - // We have reached the end of the URI - if (uri.size() % 2 == 0) - { - SendPathValueForDictionary(output, *dicom); - } - else - { - SendPathValueForLeaf(output, uri.back(), *dicom, transferSyntax); - } - } -#endif - - - void ParsedDicomFile::Remove(const DicomTag& tag) - { - InvalidateCache(); - - DcmTagKey key(tag.GetGroup(), tag.GetElement()); - DcmElement* element = GetDcmtkObject().getDataset()->remove(key); - if (element != NULL) - { - delete element; - } - } - - - void ParsedDicomFile::Clear(const DicomTag& tag, - bool onlyIfExists) - { - if (tag.GetElement() == 0x0000) - { - // Prevent manually modifying generic group length tags: This is - // handled by DCMTK serialization - return; - } - - InvalidateCache(); - - DcmItem* dicom = GetDcmtkObject().getDataset(); - DcmTagKey key(tag.GetGroup(), tag.GetElement()); - - if (onlyIfExists && - !dicom->tagExists(key)) - { - // The tag is non-existing, do not clear it - } - else - { - if (!dicom->insertEmptyElement(key, OFTrue /* replace old value */).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - } - - - void ParsedDicomFile::RemovePrivateTagsInternal(const std::set* toKeep) - { - InvalidateCache(); - - DcmDataset& dataset = *GetDcmtkObject().getDataset(); - - // Loop over the dataset to detect its private tags - typedef std::list Tags; - Tags privateTags; - - for (unsigned long i = 0; i < dataset.card(); i++) - { - DcmElement* element = dataset.getElement(i); - DcmTag tag(element->getTag()); - - // Is this a private tag? - if (tag.isPrivate()) - { - bool remove = true; - - // Check whether this private tag is to be kept - if (toKeep != NULL) - { - DicomTag tmp = FromDcmtkBridge::Convert(tag); - if (toKeep->find(tmp) != toKeep->end()) - { - remove = false; // Keep it - } - } - - if (remove) - { - privateTags.push_back(element); - } - } - } - - // Loop over the detected private tags to remove them - for (Tags::iterator it = privateTags.begin(); - it != privateTags.end(); ++it) - { - DcmElement* tmp = dataset.remove(*it); - if (tmp != NULL) - { - delete tmp; - } - } - } - - - static void InsertInternal(DcmDataset& dicom, - DcmElement* element) - { - OFCondition cond = dicom.insert(element, false, false); - if (!cond.good()) - { - // This field already exists - delete element; - throw OrthancException(ErrorCode_InternalError); - } - } - - - void ParsedDicomFile::Insert(const DicomTag& tag, - const Json::Value& value, - bool decodeDataUriScheme, - const std::string& privateCreator) - { - if (tag.GetElement() == 0x0000) - { - // Prevent manually modifying generic group length tags: This is - // handled by DCMTK serialization - return; - } - - if (GetDcmtkObject().getDataset()->tagExists(ToDcmtkBridge::Convert(tag))) - { - throw OrthancException(ErrorCode_AlreadyExistingTag); - } - - if (decodeDataUriScheme && - value.type() == Json::stringValue && - (tag == DICOM_TAG_ENCAPSULATED_DOCUMENT || - tag == DICOM_TAG_PIXEL_DATA)) - { - if (EmbedContentInternal(value.asString())) - { - return; - } - } - - InvalidateCache(); - - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions); - std::unique_ptr element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding, privateCreator)); - InsertInternal(*GetDcmtkObject().getDataset(), element.release()); - } - - - void ParsedDicomFile::ReplacePlainString(const DicomTag& tag, - const std::string& utf8Value) - { - if (tag.IsPrivate()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot apply this function to private tags: " + tag.Format()); - } - else - { - Replace(tag, utf8Value, false, DicomReplaceMode_InsertIfAbsent, - "" /* not a private tag, so no private creator */); - } - } - - - void ParsedDicomFile::SetIfAbsent(const DicomTag& tag, - const std::string& utf8Value) - { - std::string currentValue; - if (!GetTagValue(currentValue, tag)) - { - ReplacePlainString(tag, utf8Value); - } - } - - - static bool CanReplaceProceed(DcmDataset& dicom, - const DcmTagKey& tag, - DicomReplaceMode mode) - { - if (dicom.findAndDeleteElement(tag).good()) - { - // This tag was existing, it has been deleted - return true; - } - else - { - // This tag was absent, act wrt. the specified "mode" - switch (mode) - { - case DicomReplaceMode_InsertIfAbsent: - return true; - - case DicomReplaceMode_ThrowIfAbsent: - throw OrthancException(ErrorCode_InexistentItem); - - case DicomReplaceMode_IgnoreIfAbsent: - return false; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - } - - - void ParsedDicomFile::UpdateStorageUid(const DicomTag& tag, - const std::string& utf8Value, - bool decodeDataUriScheme) - { - if (tag != DICOM_TAG_SOP_CLASS_UID && - tag != DICOM_TAG_SOP_INSTANCE_UID) - { - return; - } - - std::string binary; - const std::string* decoded = &utf8Value; - - if (decodeDataUriScheme && - boost::starts_with(utf8Value, URI_SCHEME_PREFIX_BINARY)) - { - std::string mime; - if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - decoded = &binary; - } - else - { - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions); - if (encoding != Encoding_Utf8) - { - binary = Toolbox::ConvertFromUtf8(utf8Value, encoding); - decoded = &binary; - } - } - - /** - * dcmodify will automatically correct 'Media Storage SOP Class - * UID' and 'Media Storage SOP Instance UID' in the metaheader, if - * you make changes to the related tags in the dataset ('SOP Class - * UID' and 'SOP Instance UID') via insert or modify mode - * options. You can disable this behaviour by using the -nmu - * option. - **/ - - if (tag == DICOM_TAG_SOP_CLASS_UID) - { - ReplacePlainString(DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID, *decoded); - } - - if (tag == DICOM_TAG_SOP_INSTANCE_UID) - { - ReplacePlainString(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID, *decoded); - } - } - - - void ParsedDicomFile::Replace(const DicomTag& tag, - const std::string& utf8Value, - bool decodeDataUriScheme, - DicomReplaceMode mode, - const std::string& privateCreator) - { - if (tag.GetElement() == 0x0000) - { - // Prevent manually modifying generic group length tags: This is - // handled by DCMTK serialization - return; - } - - InvalidateCache(); - - DcmDataset& dicom = *GetDcmtkObject().getDataset(); - if (CanReplaceProceed(dicom, ToDcmtkBridge::Convert(tag), mode)) - { - // Either the tag was previously existing (and now removed), or - // the replace mode was set to "InsertIfAbsent" - - if (decodeDataUriScheme && - (tag == DICOM_TAG_ENCAPSULATED_DOCUMENT || - tag == DICOM_TAG_PIXEL_DATA)) - { - if (EmbedContentInternal(utf8Value)) - { - return; - } - } - - std::unique_ptr element(FromDcmtkBridge::CreateElementForTag(tag, privateCreator)); - - if (!utf8Value.empty()) - { - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions); - FromDcmtkBridge::FillElementWithString(*element, utf8Value, decodeDataUriScheme, encoding); - } - - InsertInternal(dicom, element.release()); - UpdateStorageUid(tag, utf8Value, false); - } - } - - - void ParsedDicomFile::Replace(const DicomTag& tag, - const Json::Value& value, - bool decodeDataUriScheme, - DicomReplaceMode mode, - const std::string& privateCreator) - { - if (tag.GetElement() == 0x0000) - { - // Prevent manually modifying generic group length tags: This is - // handled by DCMTK serialization - return; - } - - InvalidateCache(); - - DcmDataset& dicom = *GetDcmtkObject().getDataset(); - if (CanReplaceProceed(dicom, ToDcmtkBridge::Convert(tag), mode)) - { - // Either the tag was previously existing (and now removed), or - // the replace mode was set to "InsertIfAbsent" - - if (decodeDataUriScheme && - value.type() == Json::stringValue && - (tag == DICOM_TAG_ENCAPSULATED_DOCUMENT || - tag == DICOM_TAG_PIXEL_DATA)) - { - if (EmbedContentInternal(value.asString())) - { - return; - } - } - - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions); - InsertInternal(dicom, FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding, privateCreator)); - - if (tag == DICOM_TAG_SOP_CLASS_UID || - tag == DICOM_TAG_SOP_INSTANCE_UID) - { - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - UpdateStorageUid(tag, value.asString(), decodeDataUriScheme); - } - } - } - - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void ParsedDicomFile::Answer(RestApiOutput& output) - { - std::string serialized; - if (FromDcmtkBridge::SaveToMemoryBuffer(serialized, *GetDcmtkObject().getDataset())) - { - output.AnswerBuffer(serialized, MimeType_Dicom); - } - } -#endif - - - bool ParsedDicomFile::GetTagValue(std::string& value, - const DicomTag& tag) - { - DcmTagKey k(tag.GetGroup(), tag.GetElement()); - DcmDataset& dataset = *GetDcmtkObject().getDataset(); - - if (tag.IsPrivate() || - FromDcmtkBridge::IsUnknownTag(tag) || - tag == DICOM_TAG_PIXEL_DATA || - tag == DICOM_TAG_ENCAPSULATED_DOCUMENT) - { - const Uint8* data = NULL; // This is freed in the destructor of the dataset - long unsigned int count = 0; - - if (dataset.findAndGetUint8Array(k, data, &count).good()) - { - if (count > 0) - { - assert(data != NULL); - value.assign(reinterpret_cast(data), count); - } - else - { - value.clear(); - } - - return true; - } - else - { - return false; - } - } - else - { - DcmElement* element = NULL; - if (!dataset.findAndGetElement(k, element).good() || - element == NULL) - { - return false; - } - - bool hasCodeExtensions; - Encoding encoding = DetectEncoding(hasCodeExtensions); - - std::set tmp; - std::unique_ptr v(FromDcmtkBridge::ConvertLeafElement - (*element, DicomToJsonFlags_Default, - 0, encoding, hasCodeExtensions, tmp)); - - if (v.get() == NULL || - v->IsNull()) - { - value = ""; - } - else - { - // TODO v->IsBinary() - value = v->GetContent(); - } - - return true; - } - } - - - DicomInstanceHasher ParsedDicomFile::GetHasher() - { - std::string patientId, studyUid, seriesUid, instanceUid; - - if (!GetTagValue(patientId, DICOM_TAG_PATIENT_ID)) - { - /** - * If "PatientID" is absent, be tolerant by considering it - * equals the empty string, then proceed. In Orthanc <= 1.5.6, - * an exception "Bad file format" was generated. - * https://groups.google.com/d/msg/orthanc-users/aphG_h1AHVg/rfOTtTPTAgAJ - * https://hg.orthanc-server.com/orthanc/rev/4c45e018bd3de3cfa21d6efc6734673aaaee4435 - **/ - patientId.clear(); - } - - if (!GetTagValue(studyUid, DICOM_TAG_STUDY_INSTANCE_UID) || - !GetTagValue(seriesUid, DICOM_TAG_SERIES_INSTANCE_UID) || - !GetTagValue(instanceUid, DICOM_TAG_SOP_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadFileFormat, "missing StudyInstanceUID, SeriesInstanceUID or SOPInstanceUID"); - } - - return DicomInstanceHasher(patientId, studyUid, seriesUid, instanceUid); - } - - - void ParsedDicomFile::SaveToMemoryBuffer(std::string& buffer) - { - FromDcmtkBridge::SaveToMemoryBuffer(buffer, *GetDcmtkObject().getDataset()); - } - - -#if ORTHANC_SANDBOXED == 0 - void ParsedDicomFile::SaveToFile(const std::string& path) - { - // TODO Avoid using a temporary memory buffer, write directly on disk - std::string content; - SaveToMemoryBuffer(content); - SystemToolbox::WriteFile(content, path); - } -#endif - - - ParsedDicomFile::ParsedDicomFile(bool createIdentifiers) : pimpl_(new PImpl) - { - pimpl_->file_.reset(new DcmFileFormat); - - if (createIdentifiers) - { - ReplacePlainString(DICOM_TAG_PATIENT_ID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient)); - ReplacePlainString(DICOM_TAG_STUDY_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study)); - ReplacePlainString(DICOM_TAG_SERIES_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series)); - ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance)); - } - } - - - void ParsedDicomFile::CreateFromDicomMap(const DicomMap& source, - Encoding defaultEncoding, - bool permissive) - { - pimpl_->file_.reset(new DcmFileFormat); - pimpl_->frameIndex_.reset(NULL); - - const DicomValue* tmp = source.TestAndGetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET); - - if (tmp == NULL) - { - SetEncoding(defaultEncoding); - } - else if (tmp->IsBinary()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Invalid binary string in the SpecificCharacterSet (0008,0005) tag"); - } - else if (tmp->IsNull() || - tmp->GetContent().empty()) - { - SetEncoding(defaultEncoding); - } - else - { - Encoding encoding; - - if (GetDicomEncoding(encoding, tmp->GetContent().c_str())) - { - SetEncoding(encoding); - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Unsupported value for the SpecificCharacterSet (0008,0005) tag: \"" + - tmp->GetContent() + "\""); - } - } - - for (DicomMap::Content::const_iterator - it = source.content_.begin(); it != source.content_.end(); ++it) - { - if (it->first != DICOM_TAG_SPECIFIC_CHARACTER_SET && - !it->second->IsNull()) - { - try - { - ReplacePlainString(it->first, it->second->GetContent()); - } - catch (OrthancException&) - { - if (!permissive) - { - throw; - } - } - } - } - } - - - ParsedDicomFile::ParsedDicomFile(const DicomMap& map, - Encoding defaultEncoding, - bool permissive) : - pimpl_(new PImpl) - { - CreateFromDicomMap(map, defaultEncoding, permissive); - } - - - ParsedDicomFile::ParsedDicomFile(const void* content, - size_t size) : pimpl_(new PImpl) - { - pimpl_->file_.reset(FromDcmtkBridge::LoadFromMemoryBuffer(content, size)); - } - - ParsedDicomFile::ParsedDicomFile(const std::string& content) : pimpl_(new PImpl) - { - if (content.size() == 0) - { - pimpl_->file_.reset(FromDcmtkBridge::LoadFromMemoryBuffer(NULL, 0)); - } - else - { - pimpl_->file_.reset(FromDcmtkBridge::LoadFromMemoryBuffer(&content[0], content.size())); - } - } - - - ParsedDicomFile::ParsedDicomFile(ParsedDicomFile& other, - bool keepSopInstanceUid) : - pimpl_(new PImpl) - { - pimpl_->file_.reset(dynamic_cast(other.GetDcmtkObject().clone())); - - if (!keepSopInstanceUid) - { - // Create a new instance-level identifier - ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance)); - } - } - - - ParsedDicomFile::ParsedDicomFile(DcmDataset& dicom) : pimpl_(new PImpl) - { - pimpl_->file_.reset(new DcmFileFormat(&dicom)); - } - - - ParsedDicomFile::ParsedDicomFile(DcmFileFormat& dicom) : pimpl_(new PImpl) - { - pimpl_->file_.reset(new DcmFileFormat(dicom)); - } - - - ParsedDicomFile::ParsedDicomFile(DcmFileFormat* dicom) : pimpl_(new PImpl) - { - pimpl_->file_.reset(dicom); // No cloning - } - - - DcmFileFormat& ParsedDicomFile::GetDcmtkObject() const - { - if (pimpl_->file_.get() == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "ReleaseDcmtkObject() was called"); - } - else - { - return *pimpl_->file_; - } - } - - - DcmFileFormat* ParsedDicomFile::ReleaseDcmtkObject() - { - if (pimpl_->file_.get() == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "ReleaseDcmtkObject() was called"); - } - else - { - pimpl_->frameIndex_.reset(NULL); - return pimpl_->file_.release(); - } - } - - - ParsedDicomFile* ParsedDicomFile::Clone(bool keepSopInstanceUid) - { - return new ParsedDicomFile(*this, keepSopInstanceUid); - } - - - bool ParsedDicomFile::EmbedContentInternal(const std::string& dataUriScheme) - { - std::string mimeString, content; - if (!Toolbox::DecodeDataUriScheme(mimeString, content, dataUriScheme)) - { - return false; - } - - Toolbox::ToLowerCase(mimeString); - MimeType mime = StringToMimeType(mimeString); - - switch (mime) - { - case MimeType_Png: -#if ORTHANC_ENABLE_PNG == 1 - EmbedImage(mime, content); - break; -#else - throw OrthancException(ErrorCode_NotImplemented, - "Orthanc was compiled without support of PNG"); -#endif - - case MimeType_Jpeg: -#if ORTHANC_ENABLE_JPEG == 1 - EmbedImage(mime, content); - break; -#else - throw OrthancException(ErrorCode_NotImplemented, - "Orthanc was compiled without support of JPEG"); -#endif - - case MimeType_Pam: - EmbedImage(mime, content); - break; - - case MimeType_Pdf: - EmbedPdf(content); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented, - "Unsupported MIME type for the content of a new DICOM file: " + - std::string(EnumerationToString(mime))); - } - - return true; - } - - - void ParsedDicomFile::EmbedContent(const std::string& dataUriScheme) - { - if (!EmbedContentInternal(dataUriScheme)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - void ParsedDicomFile::EmbedImage(MimeType mime, - const std::string& content) - { - switch (mime) - { - -#if ORTHANC_ENABLE_JPEG == 1 - case MimeType_Jpeg: - { - JpegReader reader; - reader.ReadFromMemory(content); - EmbedImage(reader); - break; - } -#endif - -#if ORTHANC_ENABLE_PNG == 1 - case MimeType_Png: - { - PngReader reader; - reader.ReadFromMemory(content); - EmbedImage(reader); - break; - } -#endif - - case MimeType_Pam: - { - PamReader reader; - reader.ReadFromMemory(content); - EmbedImage(reader); - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ParsedDicomFile::EmbedImage(const ImageAccessor& accessor) - { - if (accessor.GetFormat() != PixelFormat_Grayscale8 && - accessor.GetFormat() != PixelFormat_Grayscale16 && - accessor.GetFormat() != PixelFormat_SignedGrayscale16 && - accessor.GetFormat() != PixelFormat_RGB24 && - accessor.GetFormat() != PixelFormat_RGBA32) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - InvalidateCache(); - - if (accessor.GetFormat() == PixelFormat_RGBA32) - { - LOG(WARNING) << "Getting rid of the alpha channel when embedding a RGBA image inside DICOM"; - } - - // http://dicomiseasy.blogspot.be/2012/08/chapter-12-pixel-data.html - - Remove(DICOM_TAG_PIXEL_DATA); - ReplacePlainString(DICOM_TAG_COLUMNS, boost::lexical_cast(accessor.GetWidth())); - ReplacePlainString(DICOM_TAG_ROWS, boost::lexical_cast(accessor.GetHeight())); - ReplacePlainString(DICOM_TAG_SAMPLES_PER_PIXEL, "1"); - - // The "Number of frames" must only be present in multi-frame images - //ReplacePlainString(DICOM_TAG_NUMBER_OF_FRAMES, "1"); - - if (accessor.GetFormat() == PixelFormat_SignedGrayscale16) - { - ReplacePlainString(DICOM_TAG_PIXEL_REPRESENTATION, "1"); - } - else - { - ReplacePlainString(DICOM_TAG_PIXEL_REPRESENTATION, "0"); // Unsigned pixels - } - - unsigned int bytesPerPixel = 0; - - switch (accessor.GetFormat()) - { - case PixelFormat_Grayscale8: - // By default, grayscale images are MONOCHROME2 - SetIfAbsent(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2"); - - ReplacePlainString(DICOM_TAG_BITS_ALLOCATED, "8"); - ReplacePlainString(DICOM_TAG_BITS_STORED, "8"); - ReplacePlainString(DICOM_TAG_HIGH_BIT, "7"); - bytesPerPixel = 1; - break; - - case PixelFormat_RGB24: - case PixelFormat_RGBA32: - ReplacePlainString(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "RGB"); - ReplacePlainString(DICOM_TAG_SAMPLES_PER_PIXEL, "3"); - ReplacePlainString(DICOM_TAG_BITS_ALLOCATED, "8"); - ReplacePlainString(DICOM_TAG_BITS_STORED, "8"); - ReplacePlainString(DICOM_TAG_HIGH_BIT, "7"); - bytesPerPixel = 3; - - // "Planar configuration" must only present if "Samples per - // Pixel" is greater than 1 - ReplacePlainString(DICOM_TAG_PLANAR_CONFIGURATION, "0"); // Color channels are interleaved - - break; - - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - // By default, grayscale images are MONOCHROME2 - SetIfAbsent(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2"); - - ReplacePlainString(DICOM_TAG_BITS_ALLOCATED, "16"); - ReplacePlainString(DICOM_TAG_BITS_STORED, "16"); - ReplacePlainString(DICOM_TAG_HIGH_BIT, "15"); - bytesPerPixel = 2; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - assert(bytesPerPixel != 0); - - DcmTag key(DICOM_TAG_PIXEL_DATA.GetGroup(), - DICOM_TAG_PIXEL_DATA.GetElement()); - - std::unique_ptr pixels(new DcmPixelData(key)); - - unsigned int pitch = accessor.GetWidth() * bytesPerPixel; - Uint8* target = NULL; - pixels->createUint8Array(accessor.GetHeight() * pitch, target); - - for (unsigned int y = 0; y < accessor.GetHeight(); y++) - { - switch (accessor.GetFormat()) - { - case PixelFormat_RGB24: - case PixelFormat_Grayscale8: - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - { - memcpy(target, reinterpret_cast(accessor.GetConstRow(y)), pitch); - target += pitch; - break; - } - - case PixelFormat_RGBA32: - { - // The alpha channel is not supported by the DICOM standard - const Uint8* source = reinterpret_cast(accessor.GetConstRow(y)); - for (unsigned int x = 0; x < accessor.GetWidth(); x++, target += 3, source += 4) - { - target[0] = source[0]; - target[1] = source[1]; - target[2] = source[2]; - } - - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - if (!GetDcmtkObject().getDataset()->insert(pixels.release(), false, false).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - Encoding ParsedDicomFile::DetectEncoding(bool& hasCodeExtensions) const - { - return FromDcmtkBridge::DetectEncoding(hasCodeExtensions, - *GetDcmtkObject().getDataset(), - GetDefaultDicomEncoding()); - } - - - void ParsedDicomFile::SetEncoding(Encoding encoding) - { - if (encoding == Encoding_Windows1251) - { - // This Cyrillic codepage is not officially supported by the - // DICOM standard. Do not set the SpecificCharacterSet tag. - return; - } - - std::string s = GetDicomSpecificCharacterSet(encoding); - ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, s); - } - - void ParsedDicomFile::DatasetToJson(Json::Value& target, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength) - { - std::set ignoreTagLength; - FromDcmtkBridge::ExtractDicomAsJson(target, *GetDcmtkObject().getDataset(), - format, flags, maxStringLength, - GetDefaultDicomEncoding(), ignoreTagLength); - } - - - void ParsedDicomFile::DatasetToJson(Json::Value& target, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - const std::set& ignoreTagLength) - { - FromDcmtkBridge::ExtractDicomAsJson(target, *GetDcmtkObject().getDataset(), - format, flags, maxStringLength, - GetDefaultDicomEncoding(), ignoreTagLength); - } - - - void ParsedDicomFile::DatasetToJson(Json::Value& target, - const std::set& ignoreTagLength) - { - FromDcmtkBridge::ExtractDicomAsJson(target, *GetDcmtkObject().getDataset(), ignoreTagLength); - } - - - void ParsedDicomFile::DatasetToJson(Json::Value& target) - { - const std::set ignoreTagLength; - FromDcmtkBridge::ExtractDicomAsJson(target, *GetDcmtkObject().getDataset(), ignoreTagLength); - } - - - void ParsedDicomFile::HeaderToJson(Json::Value& target, - DicomToJsonFormat format) - { - FromDcmtkBridge::ExtractHeaderAsJson(target, *GetDcmtkObject().getMetaInfo(), format, DicomToJsonFlags_None, 0); - } - - - bool ParsedDicomFile::HasTag(const DicomTag& tag) const - { - DcmTag key(tag.GetGroup(), tag.GetElement()); - return GetDcmtkObject().getDataset()->tagExists(key); - } - - - void ParsedDicomFile::EmbedPdf(const std::string& pdf) - { - if (pdf.size() < 5 || // (*) - strncmp("%PDF-", pdf.c_str(), 5) != 0) - { - throw OrthancException(ErrorCode_BadFileFormat, "Not a PDF file"); - } - - InvalidateCache(); - - ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, UID_EncapsulatedPDFStorage); - ReplacePlainString(FromDcmtkBridge::Convert(DCM_Modality), "OT"); - ReplacePlainString(FromDcmtkBridge::Convert(DCM_ConversionType), "WSD"); - ReplacePlainString(FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument), MIME_PDF); - //ReplacePlainString(FromDcmtkBridge::Convert(DCM_SeriesNumber), "1"); - - std::unique_ptr element(new DcmPolymorphOBOW(DCM_EncapsulatedDocument)); - - size_t s = pdf.size(); - if (s & 1) - { - // The size of the buffer must be even - s += 1; - } - - Uint8* bytes = NULL; - OFCondition result = element->createUint8Array(s, bytes); - if (!result.good() || bytes == NULL) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - // Blank pad byte (no access violation, as "pdf.size() >= 5" because of (*) ) - bytes[s - 1] = 0; - - memcpy(bytes, pdf.c_str(), pdf.size()); - - DcmPolymorphOBOW* obj = element.release(); - result = GetDcmtkObject().getDataset()->insert(obj); - - if (!result.good()) - { - delete obj; - throw OrthancException(ErrorCode_NotEnoughMemory); - } - } - - - bool ParsedDicomFile::ExtractPdf(std::string& pdf) - { - std::string sop, mime; - - if (!GetTagValue(sop, DICOM_TAG_SOP_CLASS_UID) || - !GetTagValue(mime, FromDcmtkBridge::Convert(DCM_MIMETypeOfEncapsulatedDocument)) || - sop != UID_EncapsulatedPDFStorage || - mime != MIME_PDF) - { - return false; - } - - if (!GetTagValue(pdf, DICOM_TAG_ENCAPSULATED_DOCUMENT)) - { - return false; - } - - // Strip the possible pad byte at the end of file, because the - // encapsulated documents must always have an even length. The PDF - // format expects files to end with %%EOF followed by CR/LF. If - // the last character of the file is not a CR or LF, we assume it - // is a pad byte and remove it. - if (pdf.size() > 0) - { - char last = *pdf.rbegin(); - - if (last != 10 && last != 13) - { - pdf.resize(pdf.size() - 1); - } - } - - return true; - } - - - ParsedDicomFile* ParsedDicomFile::CreateFromJson(const Json::Value& json, - DicomFromJsonFlags flags, - const std::string& privateCreator) - { - const bool generateIdentifiers = (flags & DicomFromJsonFlags_GenerateIdentifiers) ? true : false; - const bool decodeDataUriScheme = (flags & DicomFromJsonFlags_DecodeDataUriScheme) ? true : false; - - std::unique_ptr result(new ParsedDicomFile(generateIdentifiers)); - result->SetEncoding(FromDcmtkBridge::ExtractEncoding(json, GetDefaultDicomEncoding())); - - const Json::Value::Members tags = json.getMemberNames(); - - for (size_t i = 0; i < tags.size(); i++) - { - DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); - const Json::Value& value = json[tags[i]]; - - if (tag == DICOM_TAG_PIXEL_DATA || - tag == DICOM_TAG_ENCAPSULATED_DOCUMENT) - { - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest); - } - else - { - result->EmbedContent(value.asString()); - } - } - else if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - result->Replace(tag, value, decodeDataUriScheme, DicomReplaceMode_InsertIfAbsent, privateCreator); - } - } - - return result.release(); - } - - - void ParsedDicomFile::GetRawFrame(std::string& target, - MimeType& mime, - unsigned int frameId) - { - if (pimpl_->frameIndex_.get() == NULL) - { - assert(pimpl_->file_ != NULL && - GetDcmtkObject().getDataset() != NULL); - pimpl_->frameIndex_.reset(new DicomFrameIndex(*GetDcmtkObject().getDataset())); - } - - pimpl_->frameIndex_->GetRawFrame(target, frameId); - - E_TransferSyntax transferSyntax = GetDcmtkObject().getDataset()->getCurrentXfer(); - switch (transferSyntax) - { - case EXS_JPEGProcess1: - mime = MimeType_Jpeg; - break; - - case EXS_JPEG2000LosslessOnly: - case EXS_JPEG2000: - mime = MimeType_Jpeg2000; - break; - - default: - mime = MimeType_Binary; - break; - } - } - - - void ParsedDicomFile::InvalidateCache() - { - pimpl_->frameIndex_.reset(NULL); - } - - - unsigned int ParsedDicomFile::GetFramesCount() const - { - assert(pimpl_->file_ != NULL && - GetDcmtkObject().getDataset() != NULL); - return DicomFrameIndex::GetFramesCount(*GetDcmtkObject().getDataset()); - } - - - void ParsedDicomFile::ChangeEncoding(Encoding target) - { - bool hasCodeExtensions; - Encoding source = DetectEncoding(hasCodeExtensions); - - if (source != target) // Avoid unnecessary conversion - { - ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, GetDicomSpecificCharacterSet(target)); - FromDcmtkBridge::ChangeStringEncoding(*GetDcmtkObject().getDataset(), source, hasCodeExtensions, target); - } - } - - - void ParsedDicomFile::ExtractDicomSummary(DicomMap& target) const - { - FromDcmtkBridge::ExtractDicomSummary(target, *GetDcmtkObject().getDataset()); - } - - - void ParsedDicomFile::ExtractDicomSummary(DicomMap& target, - const std::set& ignoreTagLength) const - { - FromDcmtkBridge::ExtractDicomSummary(target, *GetDcmtkObject().getDataset(), ignoreTagLength); - } - - - bool ParsedDicomFile::LookupTransferSyntax(std::string& result) - { -#if 0 - // This was the implementation in Orthanc <= 1.6.1 - - // TODO - Shouldn't "dataset.getCurrentXfer()" be used instead of - // using the meta header? - const char* value = NULL; - - if (GetDcmtkObject().getMetaInfo() != NULL && - GetDcmtkObject().getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() && - value != NULL) - { - result.assign(value); - return true; - } - else - { - return false; - } -#else - DicomTransferSyntax s; - if (FromDcmtkBridge::LookupOrthancTransferSyntax(s, GetDcmtkObject())) - { - result.assign(GetTransferSyntaxUid(s)); - return true; - } - else - { - return false; - } -#endif - } - - - bool ParsedDicomFile::LookupPhotometricInterpretation(PhotometricInterpretation& result) const - { - DcmTagKey k(DICOM_TAG_PHOTOMETRIC_INTERPRETATION.GetGroup(), - DICOM_TAG_PHOTOMETRIC_INTERPRETATION.GetElement()); - - DcmDataset& dataset = *GetDcmtkObject().getDataset(); - - const char *c = NULL; - if (dataset.findAndGetString(k, c).good() && - c != NULL) - { - result = StringToPhotometricInterpretation(c); - return true; - } - else - { - return false; - } - } - - - void ParsedDicomFile::Apply(ITagVisitor& visitor) - { - FromDcmtkBridge::Apply(*GetDcmtkObject().getDataset(), visitor, GetDefaultDicomEncoding()); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ParsedDicomFile.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_JPEG) -# error Macro ORTHANC_ENABLE_JPEG must be defined to use this file -#endif - -#if !defined(ORTHANC_ENABLE_PNG) -# error Macro ORTHANC_ENABLE_PNG must be defined to use this file -#endif - -#if !defined(ORTHANC_ENABLE_CIVETWEB) -# error Macro ORTHANC_ENABLE_CIVETWEB must be defined to use this file -#endif - -#if !defined(ORTHANC_ENABLE_MONGOOSE) -# error Macro ORTHANC_ENABLE_MONGOOSE must be defined to use this file -#endif - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if !defined(ORTHANC_ENABLE_DCMTK) -# error The macro ORTHANC_ENABLE_DCMTK must be defined -#endif - -#if ORTHANC_ENABLE_DCMTK != 1 -# error The macro ORTHANC_ENABLE_DCMTK must be set to 1 to use this file -#endif - -#include "ITagVisitor.h" -#include "../DicomFormat/DicomInstanceHasher.h" -#include "../Images/ImageAccessor.h" -#include "../IDynamicObject.h" -#include "../Toolbox.h" - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 -# include "../RestApi/RestApiOutput.h" -#endif - -#include - - -class DcmDataset; -class DcmFileFormat; - -namespace Orthanc -{ - class ParsedDicomFile : public IDynamicObject - { - private: - struct PImpl; - boost::shared_ptr pimpl_; - - ParsedDicomFile(ParsedDicomFile& other, - bool keepSopInstanceUid); - - void CreateFromDicomMap(const DicomMap& source, - Encoding defaultEncoding, - bool permissive); - - void RemovePrivateTagsInternal(const std::set* toKeep); - - void UpdateStorageUid(const DicomTag& tag, - const std::string& value, - bool decodeDataUriScheme); - - void InvalidateCache(); - - bool EmbedContentInternal(const std::string& dataUriScheme); - - ParsedDicomFile(DcmFileFormat* dicom); // This takes ownership (no clone) - - public: - ParsedDicomFile(bool createIdentifiers); // Create a minimal DICOM instance - - ParsedDicomFile(const DicomMap& map, - Encoding defaultEncoding, - bool permissive); - - ParsedDicomFile(const void* content, - size_t size); - - ParsedDicomFile(const std::string& content); - - ParsedDicomFile(DcmDataset& dicom); // This clones the DCMTK object - - ParsedDicomFile(DcmFileFormat& dicom); // This clones the DCMTK object - - static ParsedDicomFile* AcquireDcmtkObject(DcmFileFormat* dicom) // No clone here - { - return new ParsedDicomFile(dicom); - } - - DcmFileFormat& GetDcmtkObject() const; - - // The "ParsedDicomFile" object cannot be used after calling this method - DcmFileFormat* ReleaseDcmtkObject(); - - ParsedDicomFile* Clone(bool keepSopInstanceUid); - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void SendPathValue(RestApiOutput& output, - const UriComponents& uri); - - void Answer(RestApiOutput& output); -#endif - - void Remove(const DicomTag& tag); - - // Replace the DICOM tag as a NULL/empty value (e.g. for anonymization) - void Clear(const DicomTag& tag, - bool onlyIfExists); - - void Replace(const DicomTag& tag, - const std::string& utf8Value, - bool decodeDataUriScheme, - DicomReplaceMode mode, - const std::string& privateCreator /* used only for private tags */); - - void Replace(const DicomTag& tag, - const Json::Value& value, // Assumed to be encoded with UTF-8 - bool decodeDataUriScheme, - DicomReplaceMode mode, - const std::string& privateCreator /* used only for private tags */); - - void Insert(const DicomTag& tag, - const Json::Value& value, // Assumed to be encoded with UTF-8 - bool decodeDataUriScheme, - const std::string& privateCreator /* used only for private tags */); - - // Cannot be applied to private tags - void ReplacePlainString(const DicomTag& tag, - const std::string& utf8Value); - - // Cannot be applied to private tags - void SetIfAbsent(const DicomTag& tag, - const std::string& utf8Value); - - void RemovePrivateTags() - { - RemovePrivateTagsInternal(NULL); - } - - void RemovePrivateTags(const std::set& toKeep) - { - RemovePrivateTagsInternal(&toKeep); - } - - // WARNING: This function handles the decoding of strings to UTF8 - bool GetTagValue(std::string& value, - const DicomTag& tag); - - DicomInstanceHasher GetHasher(); - - void SaveToMemoryBuffer(std::string& buffer); - -#if ORTHANC_SANDBOXED == 0 - void SaveToFile(const std::string& path); -#endif - - void EmbedContent(const std::string& dataUriScheme); - - void EmbedImage(const ImageAccessor& accessor); - - void EmbedImage(MimeType mime, - const std::string& content); - - Encoding DetectEncoding(bool& hasCodeExtensions) const; - - // WARNING: This function only sets the encoding, it will not - // convert the encoding of the tags. Use "ChangeEncoding()" if need be. - void SetEncoding(Encoding encoding); - - void DatasetToJson(Json::Value& target, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength); - - void DatasetToJson(Json::Value& target, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - const std::set& ignoreTagLength); - - // This version uses the default parameters for - // FileContentType_DicomAsJson - void DatasetToJson(Json::Value& target, - const std::set& ignoreTagLength); - - void DatasetToJson(Json::Value& target); - - void HeaderToJson(Json::Value& target, - DicomToJsonFormat format); - - bool HasTag(const DicomTag& tag) const; - - void EmbedPdf(const std::string& pdf); - - bool ExtractPdf(std::string& pdf); - - void GetRawFrame(std::string& target, // OUT - MimeType& mime, // OUT - unsigned int frameId); // IN - - unsigned int GetFramesCount() const; - - static ParsedDicomFile* CreateFromJson(const Json::Value& value, - DicomFromJsonFlags flags, - const std::string& privateCreator); - - void ChangeEncoding(Encoding target); - - void ExtractDicomSummary(DicomMap& target) const; - - void ExtractDicomSummary(DicomMap& target, - const std::set& ignoreTagLength) const; - - bool LookupTransferSyntax(std::string& result); - - bool LookupPhotometricInterpretation(PhotometricInterpretation& result) const; - - void Apply(ITagVisitor& visitor); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,149 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ToDcmtkBridge.h" - -#include - -#include "../OrthancException.h" - - -namespace Orthanc -{ - DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr) - { - switch (vr) - { - case ValueRepresentation_ApplicationEntity: - return EVR_AE; - - case ValueRepresentation_AgeString: - return EVR_AS; - - case ValueRepresentation_AttributeTag: - return EVR_AT; - - case ValueRepresentation_CodeString: - return EVR_CS; - - case ValueRepresentation_Date: - return EVR_DA; - - case ValueRepresentation_DecimalString: - return EVR_DS; - - case ValueRepresentation_DateTime: - return EVR_DT; - - case ValueRepresentation_FloatingPointSingle: - return EVR_FL; - - case ValueRepresentation_FloatingPointDouble: - return EVR_FD; - - case ValueRepresentation_IntegerString: - return EVR_IS; - - case ValueRepresentation_LongString: - return EVR_LO; - - case ValueRepresentation_LongText: - return EVR_LT; - - case ValueRepresentation_OtherByte: - return EVR_OB; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_OtherDouble: - return EVR_OD;*/ - - case ValueRepresentation_OtherFloat: - return EVR_OF; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_OtherLong: - return EVR_OL;*/ - - case ValueRepresentation_OtherWord: - return EVR_OW; - - case ValueRepresentation_PersonName: - return EVR_PN; - - case ValueRepresentation_ShortString: - return EVR_SH; - - case ValueRepresentation_SignedLong: - return EVR_SL; - - case ValueRepresentation_Sequence: - return EVR_SQ; - - case ValueRepresentation_SignedShort: - return EVR_SS; - - case ValueRepresentation_ShortText: - return EVR_ST; - - case ValueRepresentation_Time: - return EVR_TM; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_UnlimitedCharacters: - return EVR_UC;*/ - - case ValueRepresentation_UniqueIdentifier: - return EVR_UI; - - case ValueRepresentation_UnsignedLong: - return EVR_UL; - - case ValueRepresentation_Unknown: - return EVR_UN; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_UniversalResource: - return EVR_UR;*/ - - case ValueRepresentation_UnsignedShort: - return EVR_US; - - case ValueRepresentation_UnlimitedText: - return EVR_UT; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/DicomParsing/ToDcmtkBridge.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if ORTHANC_ENABLE_DCMTK != 1 -# error The macro ORTHANC_ENABLE_DCMTK must be set to 1 -#endif - -#include "../DicomFormat/DicomMap.h" -#include - -namespace Orthanc -{ - class ToDcmtkBridge - { - public: - static DcmTagKey Convert(const DicomTag& tag) - { - return DcmTagKey(tag.GetGroup(), tag.GetElement()); - } - - static DcmEVR Convert(ValueRepresentation vr); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Endianness.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Endianness.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Endianness.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Endianness.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - - -/******************************************************************** - ** LINUX-LIKE ARCHITECTURES - ********************************************************************/ - -#if defined(__LSB_VERSION__) -// Linux Standard Base (LSB) does not come with be16toh, be32toh, and -// be64toh -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 0 -# include -#elif defined(__linux__) || defined(__EMSCRIPTEN__) -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 -# include -#endif - - -/******************************************************************** - ** WINDOWS ARCHITECTURES - ** - ** On Windows x86, "host" will always be little-endian ("le"). - ********************************************************************/ - -#if defined(_WIN32) -# if defined(_MSC_VER) -// Visual Studio - http://msdn.microsoft.com/en-us/library/a3140177.aspx -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 -# define be16toh(x) _byteswap_ushort(x) -# define be32toh(x) _byteswap_ulong(x) -# define be64toh(x) _byteswap_uint64(x) -# elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) -// MinGW >= 4.3 - Use builtin intrinsic for byte swapping -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 -# define be16toh(x) __builtin_bswap16(x) -# define be32toh(x) __builtin_bswap32(x) -# define be64toh(x) __builtin_bswap64(x) -# else -// MinGW <= 4.2, we must manually implement the byte swapping (*) -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 0 -# define be16toh(x) __orthanc_bswap16(x) -# define be32toh(x) __orthanc_bswap32(x) -# define be64toh(x) __orthanc_bswap64(x) -# endif - -# define htobe16(x) be16toh(x) -# define htobe32(x) be32toh(x) -# define htobe64(x) be64toh(x) - -# define htole16(x) x -# define htole32(x) x -# define htole64(x) x - -# define le16toh(x) x -# define le32toh(x) x -# define le64toh(x) x -#endif - - -/******************************************************************** - ** FREEBSD ARCHITECTURES - ********************************************************************/ - -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 -# include -#endif - - -/******************************************************************** - ** OPENBSD ARCHITECTURES - ********************************************************************/ - -#if defined(__OpenBSD__) -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 -# include -#endif - - -/******************************************************************** - ** APPLE ARCHITECTURES (including OS X) - ********************************************************************/ - -#if defined(__APPLE__) -# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 -# include -# define be16toh(x) OSSwapBigToHostInt16(x) -# define be32toh(x) OSSwapBigToHostInt32(x) -# define be64toh(x) OSSwapBigToHostInt64(x) - -# define htobe16(x) OSSwapHostToBigInt16(x) -# define htobe32(x) OSSwapHostToBigInt32(x) -# define htobe64(x) OSSwapHostToBigInt64(x) - -# define htole16(x) OSSwapHostToLittleInt16(x) -# define htole32(x) OSSwapHostToLittleInt32(x) -# define htole64(x) OSSwapHostToLittleInt64(x) - -# define le16toh(x) OSSwapLittleToHostInt16(x) -# define le32toh(x) OSSwapLittleToHostInt32(x) -# define le64toh(x) OSSwapLittleToHostInt64(x) -#endif - - -/******************************************************************** - ** PORTABLE (BUT SLOW) IMPLEMENTATION OF BYTE-SWAPPING - ********************************************************************/ - -#if ORTHANC_HAS_BUILTIN_BYTE_SWAP != 1 - -#include - -static inline uint16_t __orthanc_bswap16(uint16_t a) -{ - /** - * Note that an alternative implementation was included in Orthanc - * 1.4.0 and 1.4.1: - * - * # hg log -p -r 2706 - * - * This alternative implementation only hid an underlying problem - * with pointer alignment on some architectures, and was thus - * reverted. Check out issue #99: - * https://bitbucket.org/sjodogne/orthanc/issues/99 - **/ - return (a << 8) | (a >> 8); -} - -static inline uint32_t __orthanc_bswap32(uint32_t a) -{ - const uint8_t* p = reinterpret_cast(&a); - return (static_cast(p[0]) << 24 | - static_cast(p[1]) << 16 | - static_cast(p[2]) << 8 | - static_cast(p[3])); -} - -static inline uint64_t __orthanc_bswap64(uint64_t a) -{ - const uint8_t* p = reinterpret_cast(&a); - return (static_cast(p[0]) << 56 | - static_cast(p[1]) << 48 | - static_cast(p[2]) << 40 | - static_cast(p[3]) << 32 | - static_cast(p[4]) << 24 | - static_cast(p[5]) << 16 | - static_cast(p[6]) << 8 | - static_cast(p[7])); -} - -#if defined(_WIN32) -// Implemented above (*) -#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define be16toh(x) __orthanc_bswap16(x) -# define be32toh(x) __orthanc_bswap32(x) -# define be64toh(x) __orthanc_bswap64(x) -# define htobe16(x) __orthanc_bswap16(x) -# define htobe32(x) __orthanc_bswap32(x) -# define htobe64(x) __orthanc_bswap64(x) -# define htole16(x) x -# define htole32(x) x -# define htole64(x) x -# define le16toh(x) x -# define le32toh(x) x -# define le64toh(x) x -# elif __BYTE_ORDER == __BIG_ENDIAN -# define be16toh(x) x -# define be32toh(x) x -# define be64toh(x) x -# define htobe16(x) x -# define htobe32(x) x -# define htobe64(x) x -# define htole16(x) __orthanc_bswap16(x) -# define htole32(x) __orthanc_bswap32(x) -# define htole64(x) __orthanc_bswap64(x) -# define le16toh(x) __orthanc_bswap16(x) -# define le32toh(x) __orthanc_bswap32(x) -# define le64toh(x) __orthanc_bswap64(x) -# else -# error Please support your platform here -# endif -#else -# error Please support your platform here -#endif - -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/EnumerationDictionary.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/EnumerationDictionary.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/EnumerationDictionary.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/EnumerationDictionary.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "OrthancException.h" - -#include "Toolbox.h" -#include -#include -#include - -namespace Orthanc -{ - namespace Toolbox - { - template - class EnumerationDictionary - { - private: - typedef std::map EnumerationToString; - typedef std::map StringToEnumeration; - - EnumerationToString enumerationToString_; - StringToEnumeration stringToEnumeration_; - - public: - void Clear() - { - enumerationToString_.clear(); - stringToEnumeration_.clear(); - } - - bool Contains(Enumeration value) const - { - return enumerationToString_.find(value) != enumerationToString_.end(); - } - - void Add(Enumeration value, const std::string& str) - { - // Check if these values are free - if (enumerationToString_.find(value) != enumerationToString_.end() || - stringToEnumeration_.find(str) != stringToEnumeration_.end() || - Toolbox::IsInteger(str) /* Prevent the registration of a number */) - { - throw OrthancException(ErrorCode_BadRequest); - } - - // OK, the string is free and is not a number - enumerationToString_[value] = str; - stringToEnumeration_[str] = value; - stringToEnumeration_[boost::lexical_cast(static_cast(value))] = value; - } - - Enumeration Translate(const std::string& str) const - { - if (Toolbox::IsInteger(str)) - { - return static_cast(boost::lexical_cast(str)); - } - - typename StringToEnumeration::const_iterator - found = stringToEnumeration_.find(str); - - if (found == stringToEnumeration_.end()) - { - throw OrthancException(ErrorCode_InexistentItem); - } - else - { - return found->second; - } - } - - std::string Translate(Enumeration e) const - { - typename EnumerationToString::const_iterator - found = enumerationToString_.find(e); - - if (found == enumerationToString_.end()) - { - // No name for this item - return boost::lexical_cast(static_cast(e)); - } - else - { - return found->second; - } - } - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2302 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "Enumerations.h" - -#include "OrthancException.h" -#include "Toolbox.h" -#include "Logging.h" - -#include -#include -#include - -namespace Orthanc -{ - static const char* const MIME_CSS = "text/css"; - static const char* const MIME_DICOM = "application/dicom"; - static const char* const MIME_GIF = "image/gif"; - static const char* const MIME_GZIP = "application/gzip"; - static const char* const MIME_HTML = "text/html"; - static const char* const MIME_JAVASCRIPT = "application/javascript"; - static const char* const MIME_JPEG2000 = "image/jp2"; - static const char* const MIME_NACL = "application/x-nacl"; - static const char* const MIME_PLAIN_TEXT = "text/plain"; - static const char* const MIME_PNACL = "application/x-pnacl"; - static const char* const MIME_SVG = "image/svg+xml"; - static const char* const MIME_WEB_ASSEMBLY = "application/wasm"; - static const char* const MIME_WOFF = "application/x-font-woff"; - static const char* const MIME_WOFF2 = "font/woff2"; - static const char* const MIME_XML_2 = "text/xml"; - static const char* const MIME_ZIP = "application/zip"; - static const char* const MIME_DICOM_WEB_JSON = "application/dicom+json"; - static const char* const MIME_DICOM_WEB_XML = "application/dicom+xml"; - - // This function is autogenerated by the script - // "Resources/GenerateErrorCodes.py" - const char* EnumerationToString(ErrorCode error) - { - switch (error) - { - case ErrorCode_InternalError: - return "Internal error"; - - case ErrorCode_Success: - return "Success"; - - case ErrorCode_Plugin: - return "Error encountered within the plugin engine"; - - case ErrorCode_NotImplemented: - return "Not implemented yet"; - - case ErrorCode_ParameterOutOfRange: - return "Parameter out of range"; - - case ErrorCode_NotEnoughMemory: - return "The server hosting Orthanc is running out of memory"; - - case ErrorCode_BadParameterType: - return "Bad type for a parameter"; - - case ErrorCode_BadSequenceOfCalls: - return "Bad sequence of calls"; - - case ErrorCode_InexistentItem: - return "Accessing an inexistent item"; - - case ErrorCode_BadRequest: - return "Bad request"; - - case ErrorCode_NetworkProtocol: - return "Error in the network protocol"; - - case ErrorCode_SystemCommand: - return "Error while calling a system command"; - - case ErrorCode_Database: - return "Error with the database engine"; - - case ErrorCode_UriSyntax: - return "Badly formatted URI"; - - case ErrorCode_InexistentFile: - return "Inexistent file"; - - case ErrorCode_CannotWriteFile: - return "Cannot write to file"; - - case ErrorCode_BadFileFormat: - return "Bad file format"; - - case ErrorCode_Timeout: - return "Timeout"; - - case ErrorCode_UnknownResource: - return "Unknown resource"; - - case ErrorCode_IncompatibleDatabaseVersion: - return "Incompatible version of the database"; - - case ErrorCode_FullStorage: - return "The file storage is full"; - - case ErrorCode_CorruptedFile: - return "Corrupted file (e.g. inconsistent MD5 hash)"; - - case ErrorCode_InexistentTag: - return "Inexistent tag"; - - case ErrorCode_ReadOnly: - return "Cannot modify a read-only data structure"; - - case ErrorCode_IncompatibleImageFormat: - return "Incompatible format of the images"; - - case ErrorCode_IncompatibleImageSize: - return "Incompatible size of the images"; - - case ErrorCode_SharedLibrary: - return "Error while using a shared library (plugin)"; - - case ErrorCode_UnknownPluginService: - return "Plugin invoking an unknown service"; - - case ErrorCode_UnknownDicomTag: - return "Unknown DICOM tag"; - - case ErrorCode_BadJson: - return "Cannot parse a JSON document"; - - case ErrorCode_Unauthorized: - return "Bad credentials were provided to an HTTP request"; - - case ErrorCode_BadFont: - return "Badly formatted font file"; - - case ErrorCode_DatabasePlugin: - return "The plugin implementing a custom database back-end does not fulfill the proper interface"; - - case ErrorCode_StorageAreaPlugin: - return "Error in the plugin implementing a custom storage area"; - - case ErrorCode_EmptyRequest: - return "The request is empty"; - - case ErrorCode_NotAcceptable: - return "Cannot send a response which is acceptable according to the Accept HTTP header"; - - case ErrorCode_NullPointer: - return "Cannot handle a NULL pointer"; - - case ErrorCode_DatabaseUnavailable: - return "The database is currently not available (probably a transient situation)"; - - case ErrorCode_CanceledJob: - return "This job was canceled"; - - case ErrorCode_BadGeometry: - return "Geometry error encountered in Stone"; - - case ErrorCode_SslInitialization: - return "Cannot initialize SSL encryption, check out your certificates"; - - case ErrorCode_SQLiteNotOpened: - return "SQLite: The database is not opened"; - - case ErrorCode_SQLiteAlreadyOpened: - return "SQLite: Connection is already open"; - - case ErrorCode_SQLiteCannotOpen: - return "SQLite: Unable to open the database"; - - case ErrorCode_SQLiteStatementAlreadyUsed: - return "SQLite: This cached statement is already being referred to"; - - case ErrorCode_SQLiteExecute: - return "SQLite: Cannot execute a command"; - - case ErrorCode_SQLiteRollbackWithoutTransaction: - return "SQLite: Rolling back a nonexistent transaction (have you called Begin()?)"; - - case ErrorCode_SQLiteCommitWithoutTransaction: - return "SQLite: Committing a nonexistent transaction"; - - case ErrorCode_SQLiteRegisterFunction: - return "SQLite: Unable to register a function"; - - case ErrorCode_SQLiteFlush: - return "SQLite: Unable to flush the database"; - - case ErrorCode_SQLiteCannotRun: - return "SQLite: Cannot run a cached statement"; - - case ErrorCode_SQLiteCannotStep: - return "SQLite: Cannot step over a cached statement"; - - case ErrorCode_SQLiteBindOutOfRange: - return "SQLite: Bing a value while out of range (serious error)"; - - case ErrorCode_SQLitePrepareStatement: - return "SQLite: Cannot prepare a cached statement"; - - case ErrorCode_SQLiteTransactionAlreadyStarted: - return "SQLite: Beginning the same transaction twice"; - - case ErrorCode_SQLiteTransactionCommit: - return "SQLite: Failure when committing the transaction"; - - case ErrorCode_SQLiteTransactionBegin: - return "SQLite: Cannot start a transaction"; - - case ErrorCode_DirectoryOverFile: - return "The directory to be created is already occupied by a regular file"; - - case ErrorCode_FileStorageCannotWrite: - return "Unable to create a subdirectory or a file in the file storage"; - - case ErrorCode_DirectoryExpected: - return "The specified path does not point to a directory"; - - case ErrorCode_HttpPortInUse: - return "The TCP port of the HTTP server is privileged or already in use"; - - case ErrorCode_DicomPortInUse: - return "The TCP port of the DICOM server is privileged or already in use"; - - case ErrorCode_BadHttpStatusInRest: - return "This HTTP status is not allowed in a REST API"; - - case ErrorCode_RegularFileExpected: - return "The specified path does not point to a regular file"; - - case ErrorCode_PathToExecutable: - return "Unable to get the path to the executable"; - - case ErrorCode_MakeDirectory: - return "Cannot create a directory"; - - case ErrorCode_BadApplicationEntityTitle: - return "An application entity title (AET) cannot be empty or be longer than 16 characters"; - - case ErrorCode_NoCFindHandler: - return "No request handler factory for DICOM C-FIND SCP"; - - case ErrorCode_NoCMoveHandler: - return "No request handler factory for DICOM C-MOVE SCP"; - - case ErrorCode_NoCStoreHandler: - return "No request handler factory for DICOM C-STORE SCP"; - - case ErrorCode_NoApplicationEntityFilter: - return "No application entity filter"; - - case ErrorCode_NoSopClassOrInstance: - return "DicomUserConnection: Unable to find the SOP class and instance"; - - case ErrorCode_NoPresentationContext: - return "DicomUserConnection: No acceptable presentation context for modality"; - - case ErrorCode_DicomFindUnavailable: - return "DicomUserConnection: The C-FIND command is not supported by the remote SCP"; - - case ErrorCode_DicomMoveUnavailable: - return "DicomUserConnection: The C-MOVE command is not supported by the remote SCP"; - - case ErrorCode_CannotStoreInstance: - return "Cannot store an instance"; - - case ErrorCode_CreateDicomNotString: - return "Only string values are supported when creating DICOM instances"; - - case ErrorCode_CreateDicomOverrideTag: - return "Trying to override a value inherited from a parent module"; - - case ErrorCode_CreateDicomUseContent: - return "Use \"Content\" to inject an image into a new DICOM instance"; - - case ErrorCode_CreateDicomNoPayload: - return "No payload is present for one instance in the series"; - - case ErrorCode_CreateDicomUseDataUriScheme: - return "The payload of the DICOM instance must be specified according to Data URI scheme"; - - case ErrorCode_CreateDicomBadParent: - return "Trying to attach a new DICOM instance to an inexistent resource"; - - case ErrorCode_CreateDicomParentIsInstance: - return "Trying to attach a new DICOM instance to an instance (must be a series, study or patient)"; - - case ErrorCode_CreateDicomParentEncoding: - return "Unable to get the encoding of the parent resource"; - - case ErrorCode_UnknownModality: - return "Unknown modality"; - - case ErrorCode_BadJobOrdering: - return "Bad ordering of filters in a job"; - - case ErrorCode_JsonToLuaTable: - return "Cannot convert the given JSON object to a Lua table"; - - case ErrorCode_CannotCreateLua: - return "Cannot create the Lua context"; - - case ErrorCode_CannotExecuteLua: - return "Cannot execute a Lua command"; - - case ErrorCode_LuaAlreadyExecuted: - return "Arguments cannot be pushed after the Lua function is executed"; - - case ErrorCode_LuaBadOutput: - return "The Lua function does not give the expected number of outputs"; - - case ErrorCode_NotLuaPredicate: - return "The Lua function is not a predicate (only true/false outputs allowed)"; - - case ErrorCode_LuaReturnsNoString: - return "The Lua function does not return a string"; - - case ErrorCode_StorageAreaAlreadyRegistered: - return "Another plugin has already registered a custom storage area"; - - case ErrorCode_DatabaseBackendAlreadyRegistered: - return "Another plugin has already registered a custom database back-end"; - - case ErrorCode_DatabaseNotInitialized: - return "Plugin trying to call the database during its initialization"; - - case ErrorCode_SslDisabled: - return "Orthanc has been built without SSL support"; - - case ErrorCode_CannotOrderSlices: - return "Unable to order the slices of the series"; - - case ErrorCode_NoWorklistHandler: - return "No request handler factory for DICOM C-Find Modality SCP"; - - case ErrorCode_AlreadyExistingTag: - return "Cannot override the value of a tag that already exists"; - - case ErrorCode_NoCGetHandler: - return "No request handler factory for DICOM C-GET SCP"; - - case ErrorCode_NoStorageCommitmentHandler: - return "No request handler factory for DICOM N-ACTION SCP (storage commitment)"; - - case ErrorCode_UnsupportedMediaType: - return "Unsupported media type"; - - default: - if (error >= ErrorCode_START_PLUGINS) - { - return "Error encountered within some plugin"; - } - else - { - return "Unknown error code"; - } - } - } - - - const char* EnumerationToString(HttpMethod method) - { - switch (method) - { - case HttpMethod_Get: - return "GET"; - - case HttpMethod_Post: - return "POST"; - - case HttpMethod_Delete: - return "DELETE"; - - case HttpMethod_Put: - return "PUT"; - - default: - return "?"; - } - } - - - const char* EnumerationToString(HttpStatus status) - { - switch (status) - { - case HttpStatus_100_Continue: - return "Continue"; - - case HttpStatus_101_SwitchingProtocols: - return "Switching Protocols"; - - case HttpStatus_102_Processing: - return "Processing"; - - case HttpStatus_200_Ok: - return "OK"; - - case HttpStatus_201_Created: - return "Created"; - - case HttpStatus_202_Accepted: - return "Accepted"; - - case HttpStatus_203_NonAuthoritativeInformation: - return "Non-Authoritative Information"; - - case HttpStatus_204_NoContent: - return "No Content"; - - case HttpStatus_205_ResetContent: - return "Reset Content"; - - case HttpStatus_206_PartialContent: - return "Partial Content"; - - case HttpStatus_207_MultiStatus: - return "Multi-Status"; - - case HttpStatus_208_AlreadyReported: - return "Already Reported"; - - case HttpStatus_226_IMUsed: - return "IM Used"; - - case HttpStatus_300_MultipleChoices: - return "Multiple Choices"; - - case HttpStatus_301_MovedPermanently: - return "Moved Permanently"; - - case HttpStatus_302_Found: - return "Found"; - - case HttpStatus_303_SeeOther: - return "See Other"; - - case HttpStatus_304_NotModified: - return "Not Modified"; - - case HttpStatus_305_UseProxy: - return "Use Proxy"; - - case HttpStatus_307_TemporaryRedirect: - return "Temporary Redirect"; - - case HttpStatus_400_BadRequest: - return "Bad Request"; - - case HttpStatus_401_Unauthorized: - return "Unauthorized"; - - case HttpStatus_402_PaymentRequired: - return "Payment Required"; - - case HttpStatus_403_Forbidden: - return "Forbidden"; - - case HttpStatus_404_NotFound: - return "Not Found"; - - case HttpStatus_405_MethodNotAllowed: - return "Method Not Allowed"; - - case HttpStatus_406_NotAcceptable: - return "Not Acceptable"; - - case HttpStatus_407_ProxyAuthenticationRequired: - return "Proxy Authentication Required"; - - case HttpStatus_408_RequestTimeout: - return "Request Timeout"; - - case HttpStatus_409_Conflict: - return "Conflict"; - - case HttpStatus_410_Gone: - return "Gone"; - - case HttpStatus_411_LengthRequired: - return "Length Required"; - - case HttpStatus_412_PreconditionFailed: - return "Precondition Failed"; - - case HttpStatus_413_RequestEntityTooLarge: - return "Request Entity Too Large"; - - case HttpStatus_414_RequestUriTooLong: - return "Request-URI Too Long"; - - case HttpStatus_415_UnsupportedMediaType: - return "Unsupported Media Type"; - - case HttpStatus_416_RequestedRangeNotSatisfiable: - return "Requested Range Not Satisfiable"; - - case HttpStatus_417_ExpectationFailed: - return "Expectation Failed"; - - case HttpStatus_422_UnprocessableEntity: - return "Unprocessable Entity"; - - case HttpStatus_423_Locked: - return "Locked"; - - case HttpStatus_424_FailedDependency: - return "Failed Dependency"; - - case HttpStatus_426_UpgradeRequired: - return "Upgrade Required"; - - case HttpStatus_500_InternalServerError: - return "Internal Server Error"; - - case HttpStatus_501_NotImplemented: - return "Not Implemented"; - - case HttpStatus_502_BadGateway: - return "Bad Gateway"; - - case HttpStatus_503_ServiceUnavailable: - return "Service Unavailable"; - - case HttpStatus_504_GatewayTimeout: - return "Gateway Timeout"; - - case HttpStatus_505_HttpVersionNotSupported: - return "HTTP Version Not Supported"; - - case HttpStatus_506_VariantAlsoNegotiates: - return "Variant Also Negotiates"; - - case HttpStatus_507_InsufficientStorage: - return "Insufficient Storage"; - - case HttpStatus_509_BandwidthLimitExceeded: - return "Bandwidth Limit Exceeded"; - - case HttpStatus_510_NotExtended: - return "Not Extended"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ResourceType type) - { - switch (type) - { - case ResourceType_Patient: - return "Patient"; - - case ResourceType_Study: - return "Study"; - - case ResourceType_Series: - return "Series"; - - case ResourceType_Instance: - return "Instance"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ImageFormat format) - { - switch (format) - { - case ImageFormat_Png: - return "Png"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(Encoding encoding) - { - switch (encoding) - { - case Encoding_Ascii: - return "Ascii"; - - case Encoding_Utf8: - return "Utf8"; - - case Encoding_Latin1: - return "Latin1"; - - case Encoding_Latin2: - return "Latin2"; - - case Encoding_Latin3: - return "Latin3"; - - case Encoding_Latin4: - return "Latin4"; - - case Encoding_Latin5: - return "Latin5"; - - case Encoding_Cyrillic: - return "Cyrillic"; - - case Encoding_Windows1251: - return "Windows1251"; - - case Encoding_Arabic: - return "Arabic"; - - case Encoding_Greek: - return "Greek"; - - case Encoding_Hebrew: - return "Hebrew"; - - case Encoding_Thai: - return "Thai"; - - case Encoding_Japanese: - return "Japanese"; - - case Encoding_Chinese: - return "Chinese"; - - case Encoding_Korean: - return "Korean"; - - case Encoding_JapaneseKanji: - return "JapaneseKanji"; - - case Encoding_SimplifiedChinese: - return "SimplifiedChinese"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(PhotometricInterpretation photometric) - { - switch (photometric) - { - case PhotometricInterpretation_RGB: - return "RGB"; - - case PhotometricInterpretation_Monochrome1: - return "MONOCHROME1"; - - case PhotometricInterpretation_Monochrome2: - return "MONOCHROME2"; - - case PhotometricInterpretation_ARGB: - return "ARGB"; - - case PhotometricInterpretation_CMYK: - return "CMYK"; - - case PhotometricInterpretation_HSV: - return "HSV"; - - case PhotometricInterpretation_Palette: - return "PALETTE COLOR"; - - case PhotometricInterpretation_YBRFull: - return "YBR_FULL"; - - case PhotometricInterpretation_YBRFull422: - return "YBR_FULL_422"; - - case PhotometricInterpretation_YBRPartial420: - return "YBR_PARTIAL_420"; - - case PhotometricInterpretation_YBRPartial422: - return "YBR_PARTIAL_422"; - - case PhotometricInterpretation_YBR_ICT: - return "YBR_ICT"; - - case PhotometricInterpretation_YBR_RCT: - return "YBR_RCT"; - - case PhotometricInterpretation_Unknown: - return "Unknown"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(RequestOrigin origin) - { - switch (origin) - { - case RequestOrigin_Unknown: - return "Unknown"; - - case RequestOrigin_DicomProtocol: - return "DicomProtocol"; - - case RequestOrigin_RestApi: - return "RestApi"; - - case RequestOrigin_Plugins: - return "Plugins"; - - case RequestOrigin_Lua: - return "Lua"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(LogLevel level) - { - switch (level) - { - case LogLevel_Error: - return "ERROR"; - - case LogLevel_Warning: - return "WARNING"; - - case LogLevel_Info: - return "INFO"; - - case LogLevel_Trace: - return "TRACE"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(PixelFormat format) - { - switch (format) - { - case PixelFormat_RGB24: - return "RGB24"; - - case PixelFormat_RGBA32: - return "RGBA32"; - - case PixelFormat_BGRA32: - return "BGRA32"; - - case PixelFormat_Grayscale8: - return "Grayscale (unsigned 8bpp)"; - - case PixelFormat_Grayscale16: - return "Grayscale (unsigned 16bpp)"; - - case PixelFormat_SignedGrayscale16: - return "Grayscale (signed 16bpp)"; - - case PixelFormat_Float32: - return "Grayscale (float 32bpp)"; - - case PixelFormat_Grayscale32: - return "Grayscale (unsigned 32bpp)"; - - case PixelFormat_Grayscale64: - return "Grayscale (unsigned 64bpp)"; - - case PixelFormat_RGB48: - return "RGB48"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ModalityManufacturer manufacturer) - { - switch (manufacturer) - { - case ModalityManufacturer_Generic: - return "Generic"; - - case ModalityManufacturer_GenericNoWildcardInDates: - return "GenericNoWildcardInDates"; - - case ModalityManufacturer_GenericNoUniversalWildcard: - return "GenericNoUniversalWildcard"; - - case ModalityManufacturer_StoreScp: - return "StoreScp"; - - case ModalityManufacturer_Vitrea: - return "Vitrea"; - - case ModalityManufacturer_GE: - return "GE"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(DicomRequestType type) - { - switch (type) - { - case DicomRequestType_Echo: - return "Echo"; - break; - - case DicomRequestType_Find: - return "Find"; - break; - - case DicomRequestType_Get: - return "Get"; - break; - - case DicomRequestType_Move: - return "Move"; - break; - - case DicomRequestType_Store: - return "Store"; - break; - - case DicomRequestType_NAction: - return "N-ACTION"; - break; - - case DicomRequestType_NEventReport: - return "N-EVENT-REPORT"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(TransferSyntax syntax) - { - switch (syntax) - { - case TransferSyntax_Deflated: - return "Deflated"; - - case TransferSyntax_Jpeg: - return "JPEG"; - - case TransferSyntax_Jpeg2000: - return "JPEG2000"; - - case TransferSyntax_JpegLossless: - return "JPEG Lossless"; - - case TransferSyntax_Jpip: - return "JPIP"; - - case TransferSyntax_Mpeg2: - return "MPEG2"; - - case TransferSyntax_Mpeg4: - return "MPEG4"; - - case TransferSyntax_Rle: - return "RLE"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(DicomVersion version) - { - switch (version) - { - case DicomVersion_2008: - return "2008"; - break; - - case DicomVersion_2017c: - return "2017c"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ValueRepresentation vr) - { - switch (vr) - { - case ValueRepresentation_ApplicationEntity: // AE - return "AE"; - - case ValueRepresentation_AgeString: // AS - return "AS"; - - case ValueRepresentation_AttributeTag: // AT (2 x uint16_t) - return "AT"; - - case ValueRepresentation_CodeString: // CS - return "CS"; - - case ValueRepresentation_Date: // DA - return "DA"; - - case ValueRepresentation_DecimalString: // DS - return "DS"; - - case ValueRepresentation_DateTime: // DT - return "DT"; - - case ValueRepresentation_FloatingPointSingle: // FL (float) - return "FL"; - - case ValueRepresentation_FloatingPointDouble: // FD (double) - return "FD"; - - case ValueRepresentation_IntegerString: // IS - return "IS"; - - case ValueRepresentation_LongString: // LO - return "LO"; - - case ValueRepresentation_LongText: // LT - return "LT"; - - case ValueRepresentation_OtherByte: // OB - return "OB"; - - case ValueRepresentation_OtherDouble: // OD - return "OD"; - - case ValueRepresentation_OtherFloat: // OF - return "OF"; - - case ValueRepresentation_OtherLong: // OL - return "OL"; - - case ValueRepresentation_OtherWord: // OW - return "OW"; - - case ValueRepresentation_PersonName: // PN - return "PN"; - - case ValueRepresentation_ShortString: // SH - return "SH"; - - case ValueRepresentation_SignedLong: // SL (int32_t) - return "SL"; - - case ValueRepresentation_Sequence: // SQ - return "SQ"; - - case ValueRepresentation_SignedShort: // SS (int16_t) - return "SS"; - - case ValueRepresentation_ShortText: // ST - return "ST"; - - case ValueRepresentation_Time: // TM - return "TM"; - - case ValueRepresentation_UnlimitedCharacters: // UC - return "UC"; - - case ValueRepresentation_UniqueIdentifier: // UI (UID) - return "UI"; - - case ValueRepresentation_UnsignedLong: // UL (uint32_t) - return "UL"; - - case ValueRepresentation_Unknown: // UN - return "UN"; - - case ValueRepresentation_UniversalResource: // UR (URI or URL) - return "UR"; - - case ValueRepresentation_UnsignedShort: // US (uint16_t) - return "US"; - - case ValueRepresentation_UnlimitedText: // UT - return "UT"; - - case ValueRepresentation_NotSupported: - return "Not supported"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(JobState state) - { - switch (state) - { - case JobState_Pending: - return "Pending"; - - case JobState_Running: - return "Running"; - - case JobState_Success: - return "Success"; - - case JobState_Failure: - return "Failure"; - - case JobState_Paused: - return "Paused"; - - case JobState_Retry: - return "Retry"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(MimeType mime) - { - switch (mime) - { - case MimeType_Binary: - return MIME_BINARY; - - case MimeType_Dicom: - return MIME_DICOM; - - case MimeType_Jpeg: - return MIME_JPEG; - - case MimeType_Jpeg2000: - return MIME_JPEG2000; - - case MimeType_Json: - return MIME_JSON; - - case MimeType_Pdf: - return MIME_PDF; - - case MimeType_Png: - return MIME_PNG; - - case MimeType_Xml: - return MIME_XML; - - case MimeType_PlainText: - return MIME_PLAIN_TEXT; - - case MimeType_Pam: - return MIME_PAM; - - case MimeType_Html: - return MIME_HTML; - - case MimeType_Gzip: - return MIME_GZIP; - - case MimeType_JavaScript: - return MIME_JAVASCRIPT; - - case MimeType_Css: - return MIME_CSS; - - case MimeType_WebAssembly: - return MIME_WEB_ASSEMBLY; - - case MimeType_Gif: - return MIME_GIF; - - case MimeType_Zip: - return MIME_ZIP; - - case MimeType_NaCl: - return MIME_NACL; - - case MimeType_PNaCl: - return MIME_PNACL; - - case MimeType_Svg: - return MIME_SVG; - - case MimeType_Woff: - return MIME_WOFF; - - case MimeType_Woff2: - return MIME_WOFF2; - - case MimeType_PrometheusText: - // https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format - return "text/plain; version=0.0.4"; - - case MimeType_DicomWebJson: - return MIME_DICOM_WEB_JSON; - - case MimeType_DicomWebXml: - return MIME_DICOM_WEB_XML; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(Endianness endianness) - { - switch (endianness) - { - case Endianness_Little: - return "Little-endian"; - - case Endianness_Big: - return "Big-endian"; - - case Endianness_Unknown: - return "Unknown endianness"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(StorageCommitmentFailureReason reason) - { - switch (reason) - { - case StorageCommitmentFailureReason_Success: - return "Success"; - - case StorageCommitmentFailureReason_ProcessingFailure: - return "A general failure in processing the operation was encountered"; - - case StorageCommitmentFailureReason_NoSuchObjectInstance: - return "One or more of the elements in the Referenced SOP " - "Instance Sequence was not available"; - - case StorageCommitmentFailureReason_ResourceLimitation: - return "The SCP does not currently have enough resources to " - "store the requested SOP Instance(s)"; - - case StorageCommitmentFailureReason_ReferencedSOPClassNotSupported: - return "Storage Commitment has been requested for a SOP Instance " - "with a SOP Class that is not supported by the SCP"; - - case StorageCommitmentFailureReason_ClassInstanceConflict: - return "The SOP Class of an element in the Referenced SOP Instance Sequence " - "did not correspond to the SOP class registered for this SOP Instance at the SCP"; - - case StorageCommitmentFailureReason_DuplicateTransactionUID: - return "The Transaction UID of the Storage Commitment Request is already in use"; - - default: - return "Unknown failure reason"; - } - } - - - Encoding StringToEncoding(const char* encoding) - { - std::string s(encoding); - Toolbox::ToUpperCase(s); - - if (s == "UTF8") - { - return Encoding_Utf8; - } - - if (s == "ASCII") - { - return Encoding_Ascii; - } - - if (s == "LATIN1") - { - return Encoding_Latin1; - } - - if (s == "LATIN2") - { - return Encoding_Latin2; - } - - if (s == "LATIN3") - { - return Encoding_Latin3; - } - - if (s == "LATIN4") - { - return Encoding_Latin4; - } - - if (s == "LATIN5") - { - return Encoding_Latin5; - } - - if (s == "CYRILLIC") - { - return Encoding_Cyrillic; - } - - if (s == "WINDOWS1251") - { - return Encoding_Windows1251; - } - - if (s == "ARABIC") - { - return Encoding_Arabic; - } - - if (s == "GREEK") - { - return Encoding_Greek; - } - - if (s == "HEBREW") - { - return Encoding_Hebrew; - } - - if (s == "THAI") - { - return Encoding_Thai; - } - - if (s == "JAPANESE") - { - return Encoding_Japanese; - } - - if (s == "CHINESE") - { - return Encoding_Chinese; - } - - if (s == "KOREAN") - { - return Encoding_Korean; - } - - if (s == "JAPANESEKANJI") - { - return Encoding_JapaneseKanji; - } - - if (s == "SIMPLIFIEDCHINESE") - { - return Encoding_SimplifiedChinese; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - ResourceType StringToResourceType(const char* type) - { - std::string s(type); - Toolbox::ToUpperCase(s); - - if (s == "PATIENT" || s == "PATIENTS") - { - return ResourceType_Patient; - } - else if (s == "STUDY" || s == "STUDIES") - { - return ResourceType_Study; - } - else if (s == "SERIES") - { - return ResourceType_Series; - } - else if (s == "INSTANCE" || s == "IMAGE" || - s == "INSTANCES" || s == "IMAGES") - { - return ResourceType_Instance; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - ImageFormat StringToImageFormat(const char* format) - { - std::string s(format); - Toolbox::ToUpperCase(s); - - if (s == "PNG") - { - return ImageFormat_Png; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - LogLevel StringToLogLevel(const char *level) - { - if (strcmp(level, "ERROR") == 0) - { - return LogLevel_Error; - } - else if (strcmp(level, "WARNING") == 0) - { - return LogLevel_Warning; - } - else if (strcmp(level, "INFO") == 0) - { - return LogLevel_Info; - } - else if (strcmp(level, "TRACE") == 0) - { - return LogLevel_Trace; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - ValueRepresentation StringToValueRepresentation(const std::string& vr, - bool throwIfUnsupported) - { - if (vr == "AE") - { - return ValueRepresentation_ApplicationEntity; - } - else if (vr == "AS") - { - return ValueRepresentation_AgeString; - } - else if (vr == "AT") - { - return ValueRepresentation_AttributeTag; - } - else if (vr == "CS") - { - return ValueRepresentation_CodeString; - } - else if (vr == "DA") - { - return ValueRepresentation_Date; - } - else if (vr == "DS") - { - return ValueRepresentation_DecimalString; - } - else if (vr == "DT") - { - return ValueRepresentation_DateTime; - } - else if (vr == "FL") - { - return ValueRepresentation_FloatingPointSingle; - } - else if (vr == "FD") - { - return ValueRepresentation_FloatingPointDouble; - } - else if (vr == "IS") - { - return ValueRepresentation_IntegerString; - } - else if (vr == "LO") - { - return ValueRepresentation_LongString; - } - else if (vr == "LT") - { - return ValueRepresentation_LongText; - } - else if (vr == "OB") - { - return ValueRepresentation_OtherByte; - } - else if (vr == "OD") - { - return ValueRepresentation_OtherDouble; - } - else if (vr == "OF") - { - return ValueRepresentation_OtherFloat; - } - else if (vr == "OL") - { - return ValueRepresentation_OtherLong; - } - else if (vr == "OW") - { - return ValueRepresentation_OtherWord; - } - else if (vr == "PN") - { - return ValueRepresentation_PersonName; - } - else if (vr == "SH") - { - return ValueRepresentation_ShortString; - } - else if (vr == "SL") - { - return ValueRepresentation_SignedLong; - } - else if (vr == "SQ") - { - return ValueRepresentation_Sequence; - } - else if (vr == "SS") - { - return ValueRepresentation_SignedShort; - } - else if (vr == "ST") - { - return ValueRepresentation_ShortText; - } - else if (vr == "TM") - { - return ValueRepresentation_Time; - } - else if (vr == "UC") - { - return ValueRepresentation_UnlimitedCharacters; - } - else if (vr == "UI") - { - return ValueRepresentation_UniqueIdentifier; - } - else if (vr == "UL") - { - return ValueRepresentation_UnsignedLong; - } - else if (vr == "UN") - { - return ValueRepresentation_Unknown; - } - else if (vr == "UR") - { - return ValueRepresentation_UniversalResource; - } - else if (vr == "US") - { - return ValueRepresentation_UnsignedShort; - } - else if (vr == "UT") - { - return ValueRepresentation_UnlimitedText; - } - else - { - std::string s = "Unsupported value representation encountered: " + vr; - - if (throwIfUnsupported) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, s); - } - else - { - LOG(INFO) << s; - return ValueRepresentation_NotSupported; - } - } - } - - - PhotometricInterpretation StringToPhotometricInterpretation(const char* value) - { - // http://dicom.nema.org/medical/dicom/2017a/output/chtml/part03/sect_C.7.6.3.html#sect_C.7.6.3.1.2 - std::string s(value); - - if (s == "MONOCHROME1") - { - return PhotometricInterpretation_Monochrome1; - } - - if (s == "MONOCHROME2") - { - return PhotometricInterpretation_Monochrome2; - } - - if (s == "PALETTE COLOR") - { - return PhotometricInterpretation_Palette; - } - - if (s == "RGB") - { - return PhotometricInterpretation_RGB; - } - - if (s == "HSV") - { - return PhotometricInterpretation_HSV; - } - - if (s == "ARGB") - { - return PhotometricInterpretation_ARGB; - } - - if (s == "CMYK") - { - return PhotometricInterpretation_CMYK; - } - - if (s == "YBR_FULL") - { - return PhotometricInterpretation_YBRFull; - } - - if (s == "YBR_FULL_422") - { - return PhotometricInterpretation_YBRFull422; - } - - if (s == "YBR_PARTIAL_422") - { - return PhotometricInterpretation_YBRPartial422; - } - - if (s == "YBR_PARTIAL_420") - { - return PhotometricInterpretation_YBRPartial420; - } - - if (s == "YBR_ICT") - { - return PhotometricInterpretation_YBR_ICT; - } - - if (s == "YBR_RCT") - { - return PhotometricInterpretation_YBR_RCT; - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer) - { - ModalityManufacturer result; - bool obsolete = false; - - if (manufacturer == "Generic") - { - return ModalityManufacturer_Generic; - } - else if (manufacturer == "GenericNoWildcardInDates") - { - return ModalityManufacturer_GenericNoWildcardInDates; - } - else if (manufacturer == "GenericNoUniversalWildcard") - { - return ModalityManufacturer_GenericNoUniversalWildcard; - } - else if (manufacturer == "StoreScp") - { - return ModalityManufacturer_StoreScp; - } - else if (manufacturer == "Vitrea") - { - return ModalityManufacturer_Vitrea; - } - else if (manufacturer == "GE") - { - return ModalityManufacturer_GE; - } - else if (manufacturer == "AgfaImpax" || - manufacturer == "SyngoVia") - { - result = ModalityManufacturer_GenericNoWildcardInDates; - obsolete = true; - } - else if (manufacturer == "EFilm2" || - manufacturer == "MedInria" || - manufacturer == "ClearCanvas" || - manufacturer == "Dcm4Chee" - ) - { - result = ModalityManufacturer_Generic; - obsolete = true; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Unknown modality manufacturer: \"" + manufacturer + "\""); - } - - if (obsolete) - { - LOG(WARNING) << "The \"" << manufacturer << "\" manufacturer is now obsolete. " - << "To guarantee compatibility with future Orthanc " - << "releases, you should replace it by \"" - << EnumerationToString(result) - << "\" in your configuration file."; - } - - return result; - } - - - DicomVersion StringToDicomVersion(const std::string& version) - { - if (version == "2008") - { - return DicomVersion_2008; - } - else if (version == "2017c") - { - return DicomVersion_2017c; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - JobState StringToJobState(const std::string& state) - { - if (state == "Pending") - { - return JobState_Pending; - } - else if (state == "Running") - { - return JobState_Running; - } - else if (state == "Success") - { - return JobState_Success; - } - else if (state == "Failure") - { - return JobState_Failure; - } - else if (state == "Paused") - { - return JobState_Paused; - } - else if (state == "Retry") - { - return JobState_Retry; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - RequestOrigin StringToRequestOrigin(const std::string& origin) - { - if (origin == "Unknown") - { - return RequestOrigin_Unknown; - } - else if (origin == "DicomProtocol") - { - return RequestOrigin_DicomProtocol; - } - else if (origin == "RestApi") - { - return RequestOrigin_RestApi; - } - else if (origin == "Plugins") - { - return RequestOrigin_Plugins; - } - else if (origin == "Lua") - { - return RequestOrigin_Lua; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - MimeType StringToMimeType(const std::string& mime) - { - if (mime == MIME_BINARY) - { - return MimeType_Binary; - } - else if (mime == MIME_DICOM) - { - return MimeType_Dicom; - } - else if (mime == MIME_JPEG) - { - return MimeType_Jpeg; - } - else if (mime == MIME_JPEG2000) - { - return MimeType_Jpeg2000; - } - else if (mime == MIME_JSON) - { - return MimeType_Json; - } - else if (mime == MIME_PDF) - { - return MimeType_Pdf; - } - else if (mime == MIME_PNG) - { - return MimeType_Png; - } - else if (mime == MIME_XML || - mime == MIME_XML_2) - { - return MimeType_Xml; - } - else if (mime == MIME_PLAIN_TEXT) - { - return MimeType_PlainText; - } - else if (mime == MIME_PAM) - { - return MimeType_Pam; - } - else if (mime == MIME_HTML) - { - return MimeType_Html; - } - else if (mime == MIME_GZIP) - { - return MimeType_Gzip; - } - else if (mime == MIME_JAVASCRIPT) - { - return MimeType_JavaScript; - } - else if (mime == MIME_CSS) - { - return MimeType_Css; - } - else if (mime == MIME_WEB_ASSEMBLY) - { - return MimeType_WebAssembly; - } - else if (mime == MIME_GIF) - { - return MimeType_Gif; - } - else if (mime == MIME_ZIP) - { - return MimeType_Zip; - } - else if (mime == MIME_NACL) - { - return MimeType_NaCl; - } - else if (mime == MIME_PNACL) - { - return MimeType_PNaCl; - } - else if (mime == MIME_SVG) - { - return MimeType_Svg; - } - else if (mime == MIME_WOFF) - { - return MimeType_Woff; - } - else if (mime == MIME_WOFF2) - { - return MimeType_Woff2; - } - else if (mime == MIME_DICOM_WEB_JSON) - { - return MimeType_DicomWebJson; - } - else if (mime == MIME_DICOM_WEB_XML) - { - return MimeType_DicomWebXml; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - unsigned int GetBytesPerPixel(PixelFormat format) - { - switch (format) - { - case PixelFormat_Grayscale8: - return 1; - - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - return 2; - - case PixelFormat_RGB24: - return 3; - - case PixelFormat_RGBA32: - case PixelFormat_BGRA32: - case PixelFormat_Grayscale32: - return 4; - - case PixelFormat_Float32: - assert(sizeof(float) == 4); - return 4; - - case PixelFormat_RGB48: - return 6; - - case PixelFormat_Grayscale64: - return 8; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool GetDicomEncoding(Encoding& encoding, - const char* specificCharacterSet) - { - std::string s = Toolbox::StripSpaces(specificCharacterSet); - Toolbox::ToUpperCase(s); - - // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2 - // https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java - if (s == "ISO_IR 6" || - s == "ISO 2022 IR 6") - { - encoding = Encoding_Ascii; - } - else if (s == "ISO_IR 192") - { - encoding = Encoding_Utf8; - } - else if (s == "ISO_IR 100" || - s == "ISO 2022 IR 100") - { - encoding = Encoding_Latin1; - } - else if (s == "ISO_IR 101" || - s == "ISO 2022 IR 101") - { - encoding = Encoding_Latin2; - } - else if (s == "ISO_IR 109" || - s == "ISO 2022 IR 109") - { - encoding = Encoding_Latin3; - } - else if (s == "ISO_IR 110" || - s == "ISO 2022 IR 110") - { - encoding = Encoding_Latin4; - } - else if (s == "ISO_IR 148" || - s == "ISO 2022 IR 148") - { - encoding = Encoding_Latin5; - } - else if (s == "ISO_IR 144" || - s == "ISO 2022 IR 144") - { - encoding = Encoding_Cyrillic; - } - else if (s == "ISO_IR 127" || - s == "ISO 2022 IR 127") - { - encoding = Encoding_Arabic; - } - else if (s == "ISO_IR 126" || - s == "ISO 2022 IR 126") - { - encoding = Encoding_Greek; - } - else if (s == "ISO_IR 138" || - s == "ISO 2022 IR 138") - { - encoding = Encoding_Hebrew; - } - else if (s == "ISO_IR 166" || - s == "ISO 2022 IR 166") - { - encoding = Encoding_Thai; - } - else if (s == "ISO_IR 13" || - s == "ISO 2022 IR 13") - { - encoding = Encoding_Japanese; - } - else if (s == "GB18030" || s == "GBK") - { - /** - * According to tumashu@163.com, "In China, many dicom file's - * 0008,0005 tag is set as "GBK", instead of "GB18030", GBK is a - * subset of GB18030, and which is used frequently in China, - * suggest support it." - * https://groups.google.com/d/msg/orthanc-users/WMM8LMbjpUc/02-1f_yFCgAJ - **/ - encoding = Encoding_Chinese; - } - else if (s == "ISO 2022 IR 149") - { - encoding = Encoding_Korean; - } - else if (s == "ISO 2022 IR 87") - { - encoding = Encoding_JapaneseKanji; - } - else if (s == "ISO 2022 IR 58") - { - encoding = Encoding_SimplifiedChinese; - } - /* - else if (s == "ISO 2022 IR 159") - { - TODO - Supplementary Kanji set - } - */ - else - { - return false; - } - - // The encoding was properly detected - return true; - } - - - ResourceType GetChildResourceType(ResourceType type) - { - switch (type) - { - case ResourceType_Patient: - return ResourceType_Study; - - case ResourceType_Study: - return ResourceType_Series; - - case ResourceType_Series: - return ResourceType_Instance; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - ResourceType GetParentResourceType(ResourceType type) - { - switch (type) - { - case ResourceType_Study: - return ResourceType_Patient; - - case ResourceType_Series: - return ResourceType_Study; - - case ResourceType_Instance: - return ResourceType_Series; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool IsResourceLevelAboveOrEqual(ResourceType level, - ResourceType reference) - { - switch (reference) - { - case ResourceType_Patient: - return (level == ResourceType_Patient); - - case ResourceType_Study: - return (level == ResourceType_Patient || - level == ResourceType_Study); - - case ResourceType_Series: - return (level == ResourceType_Patient || - level == ResourceType_Study || - level == ResourceType_Series); - - case ResourceType_Instance: - return (level == ResourceType_Patient || - level == ResourceType_Study || - level == ResourceType_Series || - level == ResourceType_Instance); - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - DicomModule GetModule(ResourceType type) - { - switch (type) - { - case ResourceType_Patient: - return DicomModule_Patient; - - case ResourceType_Study: - return DicomModule_Study; - - case ResourceType_Series: - return DicomModule_Series; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - - const char* GetDicomSpecificCharacterSet(Encoding encoding) - { - // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2 - switch (encoding) - { - case Encoding_Ascii: - return "ISO_IR 6"; - - case Encoding_Utf8: - return "ISO_IR 192"; - - case Encoding_Latin1: - return "ISO_IR 100"; - - case Encoding_Latin2: - return "ISO_IR 101"; - - case Encoding_Latin3: - return "ISO_IR 109"; - - case Encoding_Latin4: - return "ISO_IR 110"; - - case Encoding_Latin5: - return "ISO_IR 148"; - - case Encoding_Cyrillic: - return "ISO_IR 144"; - - case Encoding_Arabic: - return "ISO_IR 127"; - - case Encoding_Greek: - return "ISO_IR 126"; - - case Encoding_Hebrew: - return "ISO_IR 138"; - - case Encoding_Japanese: - return "ISO_IR 13"; - - case Encoding_Chinese: - return "GB18030"; - - case Encoding_Thai: - return "ISO_IR 166"; - - case Encoding_Korean: - return "ISO 2022 IR 149"; - - case Encoding_JapaneseKanji: - return "ISO 2022 IR 87"; - - case Encoding_SimplifiedChinese: - return "ISO 2022 IR 58"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - // This function is autogenerated by the script - // "Resources/GenerateErrorCodes.py" - HttpStatus ConvertErrorCodeToHttpStatus(ErrorCode error) - { - switch (error) - { - case ErrorCode_Success: - return HttpStatus_200_Ok; - - case ErrorCode_ParameterOutOfRange: - return HttpStatus_400_BadRequest; - - case ErrorCode_BadParameterType: - return HttpStatus_400_BadRequest; - - case ErrorCode_InexistentItem: - return HttpStatus_404_NotFound; - - case ErrorCode_BadRequest: - return HttpStatus_400_BadRequest; - - case ErrorCode_UriSyntax: - return HttpStatus_400_BadRequest; - - case ErrorCode_InexistentFile: - return HttpStatus_404_NotFound; - - case ErrorCode_BadFileFormat: - return HttpStatus_400_BadRequest; - - case ErrorCode_UnknownResource: - return HttpStatus_404_NotFound; - - case ErrorCode_InexistentTag: - return HttpStatus_404_NotFound; - - case ErrorCode_BadJson: - return HttpStatus_400_BadRequest; - - case ErrorCode_Unauthorized: - return HttpStatus_401_Unauthorized; - - case ErrorCode_NotAcceptable: - return HttpStatus_406_NotAcceptable; - - case ErrorCode_DatabaseUnavailable: - return HttpStatus_503_ServiceUnavailable; - - case ErrorCode_CreateDicomNotString: - return HttpStatus_400_BadRequest; - - case ErrorCode_CreateDicomOverrideTag: - return HttpStatus_400_BadRequest; - - case ErrorCode_CreateDicomUseContent: - return HttpStatus_400_BadRequest; - - case ErrorCode_CreateDicomNoPayload: - return HttpStatus_400_BadRequest; - - case ErrorCode_CreateDicomUseDataUriScheme: - return HttpStatus_400_BadRequest; - - case ErrorCode_CreateDicomBadParent: - return HttpStatus_400_BadRequest; - - case ErrorCode_CreateDicomParentIsInstance: - return HttpStatus_400_BadRequest; - - case ErrorCode_UnsupportedMediaType: - return HttpStatus_415_UnsupportedMediaType; - - default: - return HttpStatus_500_InternalServerError; - } - } - - - bool IsUserContentType(FileContentType type) - { - return (type >= FileContentType_StartUser && - type <= FileContentType_EndUser); - } - - - bool IsBinaryValueRepresentation(ValueRepresentation vr) - { - // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html - - switch (vr) - { - case ValueRepresentation_ApplicationEntity: // AE - case ValueRepresentation_AgeString: // AS - case ValueRepresentation_CodeString: // CS - case ValueRepresentation_Date: // DA - case ValueRepresentation_DecimalString: // DS - case ValueRepresentation_DateTime: // DT - case ValueRepresentation_IntegerString: // IS - case ValueRepresentation_LongString: // LO - case ValueRepresentation_LongText: // LT - case ValueRepresentation_PersonName: // PN - case ValueRepresentation_ShortString: // SH - case ValueRepresentation_ShortText: // ST - case ValueRepresentation_Time: // TM - case ValueRepresentation_UnlimitedCharacters: // UC - case ValueRepresentation_UniqueIdentifier: // UI (UID) - case ValueRepresentation_UniversalResource: // UR (URI or URL) - case ValueRepresentation_UnlimitedText: // UT - { - return false; - } - - /** - * Below are all the VR whose character repertoire is tagged as - * "not applicable" - **/ - case ValueRepresentation_AttributeTag: // AT (2 x uint16_t) - case ValueRepresentation_FloatingPointSingle: // FL (float) - case ValueRepresentation_FloatingPointDouble: // FD (double) - case ValueRepresentation_OtherByte: // OB - case ValueRepresentation_OtherDouble: // OD - case ValueRepresentation_OtherFloat: // OF - case ValueRepresentation_OtherLong: // OL - case ValueRepresentation_OtherWord: // OW - case ValueRepresentation_SignedLong: // SL (int32_t) - case ValueRepresentation_Sequence: // SQ - case ValueRepresentation_SignedShort: // SS (int16_t) - case ValueRepresentation_UnsignedLong: // UL (uint32_t) - case ValueRepresentation_Unknown: // UN - case ValueRepresentation_UnsignedShort: // US (uint16_t) - { - return true; - } - - case ValueRepresentation_NotSupported: - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - static boost::mutex defaultEncodingMutex_; // Should not be necessary - static Encoding defaultEncoding_ = ORTHANC_DEFAULT_DICOM_ENCODING; - - Encoding GetDefaultDicomEncoding() - { - boost::mutex::scoped_lock lock(defaultEncodingMutex_); - return defaultEncoding_; - } - - void SetDefaultDicomEncoding(Encoding encoding) - { - std::string name = EnumerationToString(encoding); - - { - boost::mutex::scoped_lock lock(defaultEncodingMutex_); - defaultEncoding_ = encoding; - } - - LOG(INFO) << "Default encoding for DICOM was changed to: " << name; - } -} - - -#include "./Enumerations_TransferSyntaxes.impl.h" diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,901 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include - - -// Macro "ORTHANC_FORCE_INLINE" forces a function/method to be inlined -#if defined(_MSC_VER) -# define ORTHANC_FORCE_INLINE __forceinline -#elif defined(__GNUC__) || defined(__clang__) || defined(__EMSCRIPTEN__) -# define ORTHANC_FORCE_INLINE inline __attribute((always_inline)) -#else -# error Please support your compiler here -#endif - - -// Macros "ORTHANC_OVERRIDE" and "ORTHANC_FINAL" wrap the "override" -// and "final" keywords introduced in C++11, to do compile-time -// checking of virtual methods -// The __cplusplus macro is broken in Visual Studio up to 15.6 and, in -// later versions, require the usage of the /Zc:__cplusplus flag -// We thus use an alternate way of checking for 'override' support -#ifdef ORTHANC_OVERRIDE_SUPPORTED -#error ORTHANC_OVERRIDE_SUPPORTED cannot be defined at this point -#endif - -#if __cplusplus >= 201103L -# define ORTHANC_OVERRIDE_SUPPORTED 1 -#else -# ifdef _MSC_VER -# if _MSC_VER >= 1600 -# define ORTHANC_OVERRIDE_SUPPORTED 1 -# endif -# endif -#endif - -#if ORTHANC_OVERRIDE_SUPPORTED -// The override keyword (C++11) is enabled -# define ORTHANC_OVERRIDE override -# define ORTHANC_FINAL final -#else -// The override keyword (C++11) is not available -# define ORTHANC_OVERRIDE -# define ORTHANC_FINAL -#endif - -namespace Orthanc -{ - static const char* const URI_SCHEME_PREFIX_BINARY = "data:application/octet-stream;base64,"; - - static const char* const MIME_BINARY = "application/octet-stream"; - static const char* const MIME_JPEG = "image/jpeg"; - static const char* const MIME_JSON = "application/json"; - static const char* const MIME_JSON_UTF8 = "application/json; charset=utf-8"; - static const char* const MIME_PDF = "application/pdf"; - static const char* const MIME_PNG = "image/png"; - static const char* const MIME_XML = "application/xml"; - static const char* const MIME_XML_UTF8 = "application/xml; charset=utf-8"; - - /** - * "No Internet Media Type (aka MIME type, content type) for PBM has - * been registered with IANA, but the unofficial value - * image/x-portable-arbitrarymap is assigned by this specification, - * to be consistent with conventional values for the older Netpbm - * formats." http://netpbm.sourceforge.net/doc/pam.html - **/ - static const char* const MIME_PAM = "image/x-portable-arbitrarymap"; - - - enum MimeType - { - MimeType_Binary, - MimeType_Css, - MimeType_Dicom, - MimeType_Gif, - MimeType_Gzip, - MimeType_Html, - MimeType_JavaScript, - MimeType_Jpeg, - MimeType_Jpeg2000, - MimeType_Json, - MimeType_NaCl, - MimeType_PNaCl, - MimeType_Pam, - MimeType_Pdf, - MimeType_PlainText, - MimeType_Png, - MimeType_Svg, - MimeType_WebAssembly, - MimeType_Xml, - MimeType_Woff, // Web Open Font Format - MimeType_Woff2, - MimeType_Zip, - MimeType_PrometheusText, // Prometheus text-based exposition format (for metrics) - MimeType_DicomWebJson, - MimeType_DicomWebXml - }; - - - enum Endianness - { - Endianness_Unknown, - Endianness_Big, - Endianness_Little - }; - - // This enumeration is autogenerated by the script - // "Resources/GenerateErrorCodes.py" - enum ErrorCode - { - ErrorCode_InternalError = -1 /*!< Internal error */, - ErrorCode_Success = 0 /*!< Success */, - ErrorCode_Plugin = 1 /*!< Error encountered within the plugin engine */, - ErrorCode_NotImplemented = 2 /*!< Not implemented yet */, - ErrorCode_ParameterOutOfRange = 3 /*!< Parameter out of range */, - ErrorCode_NotEnoughMemory = 4 /*!< The server hosting Orthanc is running out of memory */, - ErrorCode_BadParameterType = 5 /*!< Bad type for a parameter */, - ErrorCode_BadSequenceOfCalls = 6 /*!< Bad sequence of calls */, - ErrorCode_InexistentItem = 7 /*!< Accessing an inexistent item */, - ErrorCode_BadRequest = 8 /*!< Bad request */, - ErrorCode_NetworkProtocol = 9 /*!< Error in the network protocol */, - ErrorCode_SystemCommand = 10 /*!< Error while calling a system command */, - ErrorCode_Database = 11 /*!< Error with the database engine */, - ErrorCode_UriSyntax = 12 /*!< Badly formatted URI */, - ErrorCode_InexistentFile = 13 /*!< Inexistent file */, - ErrorCode_CannotWriteFile = 14 /*!< Cannot write to file */, - ErrorCode_BadFileFormat = 15 /*!< Bad file format */, - ErrorCode_Timeout = 16 /*!< Timeout */, - ErrorCode_UnknownResource = 17 /*!< Unknown resource */, - ErrorCode_IncompatibleDatabaseVersion = 18 /*!< Incompatible version of the database */, - ErrorCode_FullStorage = 19 /*!< The file storage is full */, - ErrorCode_CorruptedFile = 20 /*!< Corrupted file (e.g. inconsistent MD5 hash) */, - ErrorCode_InexistentTag = 21 /*!< Inexistent tag */, - ErrorCode_ReadOnly = 22 /*!< Cannot modify a read-only data structure */, - ErrorCode_IncompatibleImageFormat = 23 /*!< Incompatible format of the images */, - ErrorCode_IncompatibleImageSize = 24 /*!< Incompatible size of the images */, - ErrorCode_SharedLibrary = 25 /*!< Error while using a shared library (plugin) */, - ErrorCode_UnknownPluginService = 26 /*!< Plugin invoking an unknown service */, - ErrorCode_UnknownDicomTag = 27 /*!< Unknown DICOM tag */, - ErrorCode_BadJson = 28 /*!< Cannot parse a JSON document */, - ErrorCode_Unauthorized = 29 /*!< Bad credentials were provided to an HTTP request */, - ErrorCode_BadFont = 30 /*!< Badly formatted font file */, - ErrorCode_DatabasePlugin = 31 /*!< The plugin implementing a custom database back-end does not fulfill the proper interface */, - ErrorCode_StorageAreaPlugin = 32 /*!< Error in the plugin implementing a custom storage area */, - ErrorCode_EmptyRequest = 33 /*!< The request is empty */, - ErrorCode_NotAcceptable = 34 /*!< Cannot send a response which is acceptable according to the Accept HTTP header */, - ErrorCode_NullPointer = 35 /*!< Cannot handle a NULL pointer */, - ErrorCode_DatabaseUnavailable = 36 /*!< The database is currently not available (probably a transient situation) */, - ErrorCode_CanceledJob = 37 /*!< This job was canceled */, - ErrorCode_BadGeometry = 38 /*!< Geometry error encountered in Stone */, - ErrorCode_SslInitialization = 39 /*!< Cannot initialize SSL encryption, check out your certificates */, - ErrorCode_SQLiteNotOpened = 1000 /*!< SQLite: The database is not opened */, - ErrorCode_SQLiteAlreadyOpened = 1001 /*!< SQLite: Connection is already open */, - ErrorCode_SQLiteCannotOpen = 1002 /*!< SQLite: Unable to open the database */, - ErrorCode_SQLiteStatementAlreadyUsed = 1003 /*!< SQLite: This cached statement is already being referred to */, - ErrorCode_SQLiteExecute = 1004 /*!< SQLite: Cannot execute a command */, - ErrorCode_SQLiteRollbackWithoutTransaction = 1005 /*!< SQLite: Rolling back a nonexistent transaction (have you called Begin()?) */, - ErrorCode_SQLiteCommitWithoutTransaction = 1006 /*!< SQLite: Committing a nonexistent transaction */, - ErrorCode_SQLiteRegisterFunction = 1007 /*!< SQLite: Unable to register a function */, - ErrorCode_SQLiteFlush = 1008 /*!< SQLite: Unable to flush the database */, - ErrorCode_SQLiteCannotRun = 1009 /*!< SQLite: Cannot run a cached statement */, - ErrorCode_SQLiteCannotStep = 1010 /*!< SQLite: Cannot step over a cached statement */, - ErrorCode_SQLiteBindOutOfRange = 1011 /*!< SQLite: Bing a value while out of range (serious error) */, - ErrorCode_SQLitePrepareStatement = 1012 /*!< SQLite: Cannot prepare a cached statement */, - ErrorCode_SQLiteTransactionAlreadyStarted = 1013 /*!< SQLite: Beginning the same transaction twice */, - ErrorCode_SQLiteTransactionCommit = 1014 /*!< SQLite: Failure when committing the transaction */, - ErrorCode_SQLiteTransactionBegin = 1015 /*!< SQLite: Cannot start a transaction */, - ErrorCode_DirectoryOverFile = 2000 /*!< The directory to be created is already occupied by a regular file */, - ErrorCode_FileStorageCannotWrite = 2001 /*!< Unable to create a subdirectory or a file in the file storage */, - ErrorCode_DirectoryExpected = 2002 /*!< The specified path does not point to a directory */, - ErrorCode_HttpPortInUse = 2003 /*!< The TCP port of the HTTP server is privileged or already in use */, - ErrorCode_DicomPortInUse = 2004 /*!< The TCP port of the DICOM server is privileged or already in use */, - ErrorCode_BadHttpStatusInRest = 2005 /*!< This HTTP status is not allowed in a REST API */, - ErrorCode_RegularFileExpected = 2006 /*!< The specified path does not point to a regular file */, - ErrorCode_PathToExecutable = 2007 /*!< Unable to get the path to the executable */, - ErrorCode_MakeDirectory = 2008 /*!< Cannot create a directory */, - ErrorCode_BadApplicationEntityTitle = 2009 /*!< An application entity title (AET) cannot be empty or be longer than 16 characters */, - ErrorCode_NoCFindHandler = 2010 /*!< No request handler factory for DICOM C-FIND SCP */, - ErrorCode_NoCMoveHandler = 2011 /*!< No request handler factory for DICOM C-MOVE SCP */, - ErrorCode_NoCStoreHandler = 2012 /*!< No request handler factory for DICOM C-STORE SCP */, - ErrorCode_NoApplicationEntityFilter = 2013 /*!< No application entity filter */, - ErrorCode_NoSopClassOrInstance = 2014 /*!< DicomUserConnection: Unable to find the SOP class and instance */, - ErrorCode_NoPresentationContext = 2015 /*!< DicomUserConnection: No acceptable presentation context for modality */, - ErrorCode_DicomFindUnavailable = 2016 /*!< DicomUserConnection: The C-FIND command is not supported by the remote SCP */, - ErrorCode_DicomMoveUnavailable = 2017 /*!< DicomUserConnection: The C-MOVE command is not supported by the remote SCP */, - ErrorCode_CannotStoreInstance = 2018 /*!< Cannot store an instance */, - ErrorCode_CreateDicomNotString = 2019 /*!< Only string values are supported when creating DICOM instances */, - ErrorCode_CreateDicomOverrideTag = 2020 /*!< Trying to override a value inherited from a parent module */, - ErrorCode_CreateDicomUseContent = 2021 /*!< Use \"Content\" to inject an image into a new DICOM instance */, - ErrorCode_CreateDicomNoPayload = 2022 /*!< No payload is present for one instance in the series */, - ErrorCode_CreateDicomUseDataUriScheme = 2023 /*!< The payload of the DICOM instance must be specified according to Data URI scheme */, - ErrorCode_CreateDicomBadParent = 2024 /*!< Trying to attach a new DICOM instance to an inexistent resource */, - ErrorCode_CreateDicomParentIsInstance = 2025 /*!< Trying to attach a new DICOM instance to an instance (must be a series, study or patient) */, - ErrorCode_CreateDicomParentEncoding = 2026 /*!< Unable to get the encoding of the parent resource */, - ErrorCode_UnknownModality = 2027 /*!< Unknown modality */, - ErrorCode_BadJobOrdering = 2028 /*!< Bad ordering of filters in a job */, - ErrorCode_JsonToLuaTable = 2029 /*!< Cannot convert the given JSON object to a Lua table */, - ErrorCode_CannotCreateLua = 2030 /*!< Cannot create the Lua context */, - ErrorCode_CannotExecuteLua = 2031 /*!< Cannot execute a Lua command */, - ErrorCode_LuaAlreadyExecuted = 2032 /*!< Arguments cannot be pushed after the Lua function is executed */, - ErrorCode_LuaBadOutput = 2033 /*!< The Lua function does not give the expected number of outputs */, - ErrorCode_NotLuaPredicate = 2034 /*!< The Lua function is not a predicate (only true/false outputs allowed) */, - ErrorCode_LuaReturnsNoString = 2035 /*!< The Lua function does not return a string */, - ErrorCode_StorageAreaAlreadyRegistered = 2036 /*!< Another plugin has already registered a custom storage area */, - ErrorCode_DatabaseBackendAlreadyRegistered = 2037 /*!< Another plugin has already registered a custom database back-end */, - ErrorCode_DatabaseNotInitialized = 2038 /*!< Plugin trying to call the database during its initialization */, - ErrorCode_SslDisabled = 2039 /*!< Orthanc has been built without SSL support */, - ErrorCode_CannotOrderSlices = 2040 /*!< Unable to order the slices of the series */, - ErrorCode_NoWorklistHandler = 2041 /*!< No request handler factory for DICOM C-Find Modality SCP */, - ErrorCode_AlreadyExistingTag = 2042 /*!< Cannot override the value of a tag that already exists */, - ErrorCode_NoStorageCommitmentHandler = 2043 /*!< No request handler factory for DICOM N-ACTION SCP (storage commitment) */, - ErrorCode_NoCGetHandler = 2044 /*!< No request handler factory for DICOM C-GET SCP */, - ErrorCode_UnsupportedMediaType = 3000 /*!< Unsupported media type */, - ErrorCode_START_PLUGINS = 1000000 - }; - - // This enumeration is autogenerated by the script - // "Resources/GenerateTransferSyntaxes.py" - enum DicomTransferSyntax - { - DicomTransferSyntax_LittleEndianImplicit /*!< Implicit VR Little Endian */, - DicomTransferSyntax_LittleEndianExplicit /*!< Explicit VR Little Endian */, - DicomTransferSyntax_DeflatedLittleEndianExplicit /*!< Deflated Explicit VR Little Endian */, - DicomTransferSyntax_BigEndianExplicit /*!< Explicit VR Big Endian */, - DicomTransferSyntax_JPEGProcess1 /*!< JPEG Baseline (process 1, lossy) */, - DicomTransferSyntax_JPEGProcess2_4 /*!< JPEG Extended Sequential (processes 2 & 4) */, - DicomTransferSyntax_JPEGProcess3_5 /*!< JPEG Extended Sequential (lossy, 8/12 bit), arithmetic coding */, - DicomTransferSyntax_JPEGProcess6_8 /*!< JPEG Spectral Selection, Nonhierarchical (lossy, 8/12 bit) */, - DicomTransferSyntax_JPEGProcess7_9 /*!< JPEG Spectral Selection, Nonhierarchical (lossy, 8/12 bit), arithmetic coding */, - DicomTransferSyntax_JPEGProcess10_12 /*!< JPEG Full Progression, Nonhierarchical (lossy, 8/12 bit) */, - DicomTransferSyntax_JPEGProcess11_13 /*!< JPEG Full Progression, Nonhierarchical (lossy, 8/12 bit), arithmetic coding */, - DicomTransferSyntax_JPEGProcess14 /*!< JPEG Lossless, Nonhierarchical with any selection value (process 14) */, - DicomTransferSyntax_JPEGProcess15 /*!< JPEG Lossless with any selection value, arithmetic coding */, - DicomTransferSyntax_JPEGProcess16_18 /*!< JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit) */, - DicomTransferSyntax_JPEGProcess17_19 /*!< JPEG Extended Sequential, Hierarchical (lossy, 8/12 bit), arithmetic coding */, - DicomTransferSyntax_JPEGProcess20_22 /*!< JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit) */, - DicomTransferSyntax_JPEGProcess21_23 /*!< JPEG Spectral Selection, Hierarchical (lossy, 8/12 bit), arithmetic coding */, - DicomTransferSyntax_JPEGProcess24_26 /*!< JPEG Full Progression, Hierarchical (lossy, 8/12 bit) */, - DicomTransferSyntax_JPEGProcess25_27 /*!< JPEG Full Progression, Hierarchical (lossy, 8/12 bit), arithmetic coding */, - DicomTransferSyntax_JPEGProcess28 /*!< JPEG Lossless, Hierarchical */, - DicomTransferSyntax_JPEGProcess29 /*!< JPEG Lossless, Hierarchical, arithmetic coding */, - DicomTransferSyntax_JPEGProcess14SV1 /*!< JPEG Lossless, Nonhierarchical, First-Order Prediction (Processes 14 [Selection Value 1]) */, - DicomTransferSyntax_JPEGLSLossless /*!< JPEG-LS (lossless) */, - DicomTransferSyntax_JPEGLSLossy /*!< JPEG-LS (lossy or near-lossless) */, - DicomTransferSyntax_JPEG2000LosslessOnly /*!< JPEG 2000 (lossless) */, - DicomTransferSyntax_JPEG2000 /*!< JPEG 2000 (lossless or lossy) */, - DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly /*!< JPEG 2000 part 2 multicomponent extensions (lossless) */, - DicomTransferSyntax_JPEG2000Multicomponent /*!< JPEG 2000 part 2 multicomponent extensions (lossless or lossy) */, - DicomTransferSyntax_JPIPReferenced /*!< JPIP Referenced */, - DicomTransferSyntax_JPIPReferencedDeflate /*!< JPIP Referenced Deflate */, - DicomTransferSyntax_MPEG2MainProfileAtMainLevel /*!< MPEG2 Main Profile / Main Level */, - DicomTransferSyntax_MPEG2MainProfileAtHighLevel /*!< MPEG2 Main Profile / High Level */, - DicomTransferSyntax_MPEG4HighProfileLevel4_1 /*!< MPEG4 AVC/H.264 High Profile / Level 4.1 */, - DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1 /*!< MPEG4 AVC/H.264 BD-compatible High Profile / Level 4.1 */, - DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo /*!< MPEG4 AVC/H.264 High Profile / Level 4.2 For 2D Video */, - DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo /*!< MPEG4 AVC/H.264 High Profile / Level 4.2 For 3D Video */, - DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2 /*!< MPEG4 AVC/H.264 Stereo High Profile / Level 4.2 */, - DicomTransferSyntax_HEVCMainProfileLevel5_1 /*!< HEVC/H.265 Main Profile / Level 5.1 */, - DicomTransferSyntax_HEVCMain10ProfileLevel5_1 /*!< HEVC/H.265 Main 10 Profile / Level 5.1 */, - DicomTransferSyntax_RLELossless /*!< RLE - Run Length Encoding (lossless) */, - DicomTransferSyntax_RFC2557MimeEncapsulation /*!< RFC 2557 MIME Encapsulation */, - DicomTransferSyntax_XML /*!< XML Encoding */ - }; - - enum LogLevel - { - LogLevel_Error, - LogLevel_Warning, - LogLevel_Info, - LogLevel_Trace - }; - - - /** - * {summary}{The memory layout of the pixels (resp. voxels) of a 2D (resp. 3D) image.} - **/ - enum PixelFormat - { - /** - * {summary}{Color image in RGB24 format.} - * {description}{This format describes a color image. The pixels are stored in 3 - * consecutive bytes. The memory layout is RGB.} - **/ - PixelFormat_RGB24 = 1, - - /** - * {summary}{Color image in RGBA32 format.} - * {description}{This format describes a color image. The pixels are stored in 4 - * consecutive bytes. The memory layout is RGBA.} - **/ - PixelFormat_RGBA32 = 2, - - /** - * {summary}{Graylevel 8bpp image.} - * {description}{The image is graylevel. Each pixel is unsigned and stored in one byte.} - **/ - PixelFormat_Grayscale8 = 3, - - /** - * {summary}{Graylevel, unsigned 16bpp image.} - * {description}{The image is graylevel. Each pixel is unsigned and stored in two bytes.} - **/ - PixelFormat_Grayscale16 = 4, - - /** - * {summary}{Graylevel, signed 16bpp image.} - * {description}{The image is graylevel. Each pixel is signed and stored in two bytes.} - **/ - PixelFormat_SignedGrayscale16 = 5, - - /** - * {summary}{Graylevel, floating-point image.} - * {description}{The image is graylevel. Each pixel is floating-point and stored in 4 bytes.} - **/ - PixelFormat_Float32 = 6, - - // This is the memory layout for Cairo (for internal use in Stone of Orthanc) - PixelFormat_BGRA32 = 7, - - /** - * {summary}{Graylevel, unsigned 32bpp image.} - * {description}{The image is graylevel. Each pixel is unsigned and stored in 4 bytes.} - **/ - PixelFormat_Grayscale32 = 8, - - /** - * {summary}{Color image in RGB48 format.} - * {description}{This format describes a color image. The pixels are stored in 6 - * consecutive bytes. The memory layout is RGB.} - **/ - PixelFormat_RGB48 = 9, - - /** - * {summary}{Graylevel, unsigned 64bpp image.} - * {description}{The image is graylevel. Each pixel is unsigned and stored in 8 bytes.} - **/ - PixelFormat_Grayscale64 = 10 - }; - - - /** - * {summary}{The extraction mode specifies the way the values of the pixels are scaled when downloading a 2D image.} - **/ - enum ImageExtractionMode - { - /** - * {summary}{Rescaled to 8bpp.} - * {description}{The minimum value of the image is set to 0, and its maximum value is set to 255.} - **/ - ImageExtractionMode_Preview = 1, - - /** - * {summary}{Truncation to the [0, 255] range.} - **/ - ImageExtractionMode_UInt8 = 2, - - /** - * {summary}{Truncation to the [0, 65535] range.} - **/ - ImageExtractionMode_UInt16 = 3, - - /** - * {summary}{Truncation to the [-32768, 32767] range.} - **/ - ImageExtractionMode_Int16 = 4 - }; - - - /** - * Most common, non-joke and non-experimental HTTP status codes - * http://en.wikipedia.org/wiki/List_of_HTTP_status_codes - **/ - enum HttpStatus - { - HttpStatus_None = -1, - - // 1xx Informational - HttpStatus_100_Continue = 100, - HttpStatus_101_SwitchingProtocols = 101, - HttpStatus_102_Processing = 102, - - // 2xx Success - HttpStatus_200_Ok = 200, - HttpStatus_201_Created = 201, - HttpStatus_202_Accepted = 202, - HttpStatus_203_NonAuthoritativeInformation = 203, - HttpStatus_204_NoContent = 204, - HttpStatus_205_ResetContent = 205, - HttpStatus_206_PartialContent = 206, - HttpStatus_207_MultiStatus = 207, - HttpStatus_208_AlreadyReported = 208, - HttpStatus_226_IMUsed = 226, - - // 3xx Redirection - HttpStatus_300_MultipleChoices = 300, - HttpStatus_301_MovedPermanently = 301, - HttpStatus_302_Found = 302, - HttpStatus_303_SeeOther = 303, - HttpStatus_304_NotModified = 304, - HttpStatus_305_UseProxy = 305, - HttpStatus_307_TemporaryRedirect = 307, - - // 4xx Client Error - HttpStatus_400_BadRequest = 400, - HttpStatus_401_Unauthorized = 401, - HttpStatus_402_PaymentRequired = 402, - HttpStatus_403_Forbidden = 403, - HttpStatus_404_NotFound = 404, - HttpStatus_405_MethodNotAllowed = 405, - HttpStatus_406_NotAcceptable = 406, - HttpStatus_407_ProxyAuthenticationRequired = 407, - HttpStatus_408_RequestTimeout = 408, - HttpStatus_409_Conflict = 409, - HttpStatus_410_Gone = 410, - HttpStatus_411_LengthRequired = 411, - HttpStatus_412_PreconditionFailed = 412, - HttpStatus_413_RequestEntityTooLarge = 413, - HttpStatus_414_RequestUriTooLong = 414, - HttpStatus_415_UnsupportedMediaType = 415, - HttpStatus_416_RequestedRangeNotSatisfiable = 416, - HttpStatus_417_ExpectationFailed = 417, - HttpStatus_422_UnprocessableEntity = 422, - HttpStatus_423_Locked = 423, - HttpStatus_424_FailedDependency = 424, - HttpStatus_426_UpgradeRequired = 426, - - // 5xx Server Error - HttpStatus_500_InternalServerError = 500, - HttpStatus_501_NotImplemented = 501, - HttpStatus_502_BadGateway = 502, - HttpStatus_503_ServiceUnavailable = 503, - HttpStatus_504_GatewayTimeout = 504, - HttpStatus_505_HttpVersionNotSupported = 505, - HttpStatus_506_VariantAlsoNegotiates = 506, - HttpStatus_507_InsufficientStorage = 507, - HttpStatus_509_BandwidthLimitExceeded = 509, - HttpStatus_510_NotExtended = 510 - }; - - - enum HttpMethod - { - HttpMethod_Get = 0, - HttpMethod_Post = 1, - HttpMethod_Delete = 2, - HttpMethod_Put = 3 - }; - - - enum ImageFormat - { - ImageFormat_Png = 1 - }; - - - // https://en.wikipedia.org/wiki/HTTP_compression - enum HttpCompression - { - HttpCompression_None, - HttpCompression_Deflate, - HttpCompression_Gzip - }; - - - // Specific Character Sets - // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2 - enum Encoding - { - Encoding_Ascii, - Encoding_Utf8, - Encoding_Latin1, - Encoding_Latin2, - Encoding_Latin3, - Encoding_Latin4, - Encoding_Latin5, // Turkish - Encoding_Cyrillic, - Encoding_Windows1251, // Windows-1251 (commonly used for Cyrillic) - Encoding_Arabic, - Encoding_Greek, - Encoding_Hebrew, - Encoding_Thai, // TIS 620-2533 - Encoding_Japanese, // JIS X 0201 (Shift JIS): Katakana - Encoding_Chinese, // GB18030 - Chinese simplified - Encoding_JapaneseKanji, // Multibyte - JIS X 0208: Kanji - //Encoding_JapaneseSupplementaryKanji, // Multibyte - JIS X 0212: Supplementary Kanji set - Encoding_Korean, // Multibyte - KS X 1001: Hangul and Hanja - Encoding_SimplifiedChinese // ISO 2022 IR 58 - }; - - - // http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.7.6.3.1.2 - enum PhotometricInterpretation - { - PhotometricInterpretation_ARGB, // Retired - PhotometricInterpretation_CMYK, // Retired - PhotometricInterpretation_HSV, // Retired - PhotometricInterpretation_Monochrome1, - PhotometricInterpretation_Monochrome2, - PhotometricInterpretation_Palette, - PhotometricInterpretation_RGB, - PhotometricInterpretation_YBRFull, - PhotometricInterpretation_YBRFull422, - PhotometricInterpretation_YBRPartial420, - PhotometricInterpretation_YBRPartial422, - PhotometricInterpretation_YBR_ICT, - PhotometricInterpretation_YBR_RCT, - PhotometricInterpretation_Unknown - }; - - enum DicomModule - { - DicomModule_Patient, - DicomModule_Study, - DicomModule_Series, - DicomModule_Instance, - DicomModule_Image - }; - - enum RequestOrigin - { - RequestOrigin_Unknown, - RequestOrigin_DicomProtocol, - RequestOrigin_RestApi, - RequestOrigin_Plugins, - RequestOrigin_Lua - }; - - enum ServerBarrierEvent - { - ServerBarrierEvent_Stop, - ServerBarrierEvent_Reload // SIGHUP signal: reload configuration file - }; - - enum FileMode - { - FileMode_ReadBinary, - FileMode_WriteBinary - }; - - /** - * The value representations Orthanc knows about. They correspond to - * the DICOM 2016b version of the standard. - * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html - **/ - enum ValueRepresentation - { - ValueRepresentation_ApplicationEntity = 1, // AE - ValueRepresentation_AgeString = 2, // AS - ValueRepresentation_AttributeTag = 3, // AT (2 x uint16_t) - ValueRepresentation_CodeString = 4, // CS - ValueRepresentation_Date = 5, // DA - ValueRepresentation_DecimalString = 6, // DS - ValueRepresentation_DateTime = 7, // DT - ValueRepresentation_FloatingPointSingle = 8, // FL (float) - ValueRepresentation_FloatingPointDouble = 9, // FD (double) - ValueRepresentation_IntegerString = 10, // IS - ValueRepresentation_LongString = 11, // LO - ValueRepresentation_LongText = 12, // LT - ValueRepresentation_OtherByte = 13, // OB - ValueRepresentation_OtherDouble = 14, // OD - ValueRepresentation_OtherFloat = 15, // OF - ValueRepresentation_OtherLong = 16, // OL - ValueRepresentation_OtherWord = 17, // OW - ValueRepresentation_PersonName = 18, // PN - ValueRepresentation_ShortString = 19, // SH - ValueRepresentation_SignedLong = 20, // SL (int32_t) - ValueRepresentation_Sequence = 21, // SQ - ValueRepresentation_SignedShort = 22, // SS (int16_t) - ValueRepresentation_ShortText = 23, // ST - ValueRepresentation_Time = 24, // TM - ValueRepresentation_UnlimitedCharacters = 25, // UC - ValueRepresentation_UniqueIdentifier = 26, // UI (UID) - ValueRepresentation_UnsignedLong = 27, // UL (uint32_t) - ValueRepresentation_Unknown = 28, // UN - ValueRepresentation_UniversalResource = 29, // UR (URI or URL) - ValueRepresentation_UnsignedShort = 30, // US (uint16_t) - ValueRepresentation_UnlimitedText = 31, // UT - ValueRepresentation_NotSupported // Not supported by Orthanc, or tag not in dictionary - }; - - enum DicomReplaceMode - { - DicomReplaceMode_InsertIfAbsent, - DicomReplaceMode_ThrowIfAbsent, - DicomReplaceMode_IgnoreIfAbsent - }; - - enum DicomToJsonFormat - { - DicomToJsonFormat_Full, - DicomToJsonFormat_Short, - DicomToJsonFormat_Human - }; - - enum DicomToJsonFlags - { - DicomToJsonFlags_IncludeBinary = (1 << 0), - DicomToJsonFlags_IncludePrivateTags = (1 << 1), - DicomToJsonFlags_IncludeUnknownTags = (1 << 2), - DicomToJsonFlags_IncludePixelData = (1 << 3), - DicomToJsonFlags_ConvertBinaryToAscii = (1 << 4), - DicomToJsonFlags_ConvertBinaryToNull = (1 << 5), - - // Some predefined combinations - DicomToJsonFlags_None = 0, - DicomToJsonFlags_Default = (DicomToJsonFlags_IncludeBinary | - DicomToJsonFlags_IncludePixelData | - DicomToJsonFlags_IncludePrivateTags | - DicomToJsonFlags_IncludeUnknownTags | - DicomToJsonFlags_ConvertBinaryToNull) - }; - - enum DicomFromJsonFlags - { - DicomFromJsonFlags_DecodeDataUriScheme = (1 << 0), - DicomFromJsonFlags_GenerateIdentifiers = (1 << 1), - - // Some predefined combinations - DicomFromJsonFlags_None = 0 - }; - - enum DicomVersion - { - DicomVersion_2008, - DicomVersion_2017c - }; - - enum ModalityManufacturer - { - ModalityManufacturer_Generic, - ModalityManufacturer_GenericNoWildcardInDates, - ModalityManufacturer_GenericNoUniversalWildcard, - ModalityManufacturer_StoreScp, - ModalityManufacturer_Vitrea, - ModalityManufacturer_GE - }; - - enum DicomRequestType - { - DicomRequestType_Echo, - DicomRequestType_Find, - DicomRequestType_Get, - DicomRequestType_Move, - DicomRequestType_Store, - DicomRequestType_NAction, - DicomRequestType_NEventReport - }; - - enum TransferSyntax - { - TransferSyntax_Deflated, - TransferSyntax_Jpeg, - TransferSyntax_Jpeg2000, - TransferSyntax_JpegLossless, - TransferSyntax_Jpip, - TransferSyntax_Mpeg2, - TransferSyntax_Mpeg4, // New in Orthanc 1.6.0 - TransferSyntax_Rle - }; - - enum JobState - { - JobState_Pending, - JobState_Running, - JobState_Success, - JobState_Failure, - JobState_Paused, - JobState_Retry - }; - - enum JobStepCode - { - JobStepCode_Success, - JobStepCode_Failure, - JobStepCode_Continue, - JobStepCode_Retry - }; - - enum JobStopReason - { - JobStopReason_Paused, - JobStopReason_Canceled, - JobStopReason_Success, - JobStopReason_Failure, - JobStopReason_Retry - }; - - - // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.14.html#sect_C.14.1.1 - enum StorageCommitmentFailureReason - { - StorageCommitmentFailureReason_Success = 0, - - // A general failure in processing the operation was encountered - StorageCommitmentFailureReason_ProcessingFailure = 0x0110, - - // One or more of the elements in the Referenced SOP Instance - // Sequence was not available - StorageCommitmentFailureReason_NoSuchObjectInstance = 0x0112, - - // The SCP does not currently have enough resources to store the - // requested SOP Instance(s) - StorageCommitmentFailureReason_ResourceLimitation = 0x0213, - - // Storage Commitment has been requested for a SOP Instance with a - // SOP Class that is not supported by the SCP - StorageCommitmentFailureReason_ReferencedSOPClassNotSupported = 0x0122, - - // The SOP Class of an element in the Referenced SOP Instance - // Sequence did not correspond to the SOP class registered for - // this SOP Instance at the SCP - StorageCommitmentFailureReason_ClassInstanceConflict = 0x0119, - - // The Transaction UID of the Storage Commitment Request is already in use - StorageCommitmentFailureReason_DuplicateTransactionUID = 0x0131 - }; - - - enum DicomAssociationRole - { - DicomAssociationRole_Default, - DicomAssociationRole_Scu, - DicomAssociationRole_Scp - }; - - - /** - * WARNING: Do not change the explicit values in the enumerations - * below this point. This would result in incompatible databases - * between versions of Orthanc! - **/ - - enum CompressionType - { - /** - * Buffer/file that is stored as-is, in a raw fashion, without - * compression. - **/ - CompressionType_None = 1, - - /** - * Buffer that is compressed using the "deflate" algorithm (RFC - * 1951), wrapped inside the zlib data format (RFC 1950), prefixed - * with a "uint64_t" (8 bytes) that encodes the size of the - * uncompressed buffer. If the compressed buffer is empty, its - * represents an empty uncompressed buffer. This format is - * internal to Orthanc. If the 8 first bytes are skipped AND the - * buffer is non-empty, the buffer is compatible with the - * "deflate" HTTP compression. - **/ - CompressionType_ZlibWithSize = 2 - }; - - enum FileContentType - { - // If you add a value below, insert it in "PluginStorageArea" in - // the file "Plugins/Engine/OrthancPlugins.cpp" - FileContentType_Unknown = 0, - FileContentType_Dicom = 1, - FileContentType_DicomAsJson = 2, - - // Make sure that the value "65535" can be stored into this enumeration - FileContentType_StartUser = 1024, - FileContentType_EndUser = 65535 - }; - - enum ResourceType - { - ResourceType_Patient = 1, - ResourceType_Study = 2, - ResourceType_Series = 3, - ResourceType_Instance = 4 - }; - - - const char* EnumerationToString(ErrorCode code); - - const char* EnumerationToString(HttpMethod method); - - const char* EnumerationToString(HttpStatus status); - - const char* EnumerationToString(ResourceType type); - - const char* EnumerationToString(ImageFormat format); - - const char* EnumerationToString(Encoding encoding); - - const char* EnumerationToString(PhotometricInterpretation photometric); - - const char* EnumerationToString(LogLevel level); - - const char* EnumerationToString(RequestOrigin origin); - - const char* EnumerationToString(PixelFormat format); - - const char* EnumerationToString(ModalityManufacturer manufacturer); - - const char* EnumerationToString(DicomRequestType type); - - const char* EnumerationToString(TransferSyntax syntax); - - const char* EnumerationToString(DicomVersion version); - - const char* EnumerationToString(ValueRepresentation vr); - - const char* EnumerationToString(JobState state); - - const char* EnumerationToString(MimeType mime); - - const char* EnumerationToString(Endianness endianness); - - const char* EnumerationToString(StorageCommitmentFailureReason reason); - - Encoding StringToEncoding(const char* encoding); - - ResourceType StringToResourceType(const char* type); - - ImageFormat StringToImageFormat(const char* format); - - LogLevel StringToLogLevel(const char* level); - - ValueRepresentation StringToValueRepresentation(const std::string& vr, - bool throwIfUnsupported); - - PhotometricInterpretation StringToPhotometricInterpretation(const char* value); - - ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer); - - DicomVersion StringToDicomVersion(const std::string& version); - - JobState StringToJobState(const std::string& state); - - RequestOrigin StringToRequestOrigin(const std::string& origin); - - MimeType StringToMimeType(const std::string& mime); - - unsigned int GetBytesPerPixel(PixelFormat format); - - bool GetDicomEncoding(Encoding& encoding, - const char* specificCharacterSet); - - ResourceType GetChildResourceType(ResourceType type); - - ResourceType GetParentResourceType(ResourceType type); - - bool IsResourceLevelAboveOrEqual(ResourceType level, - ResourceType reference); - - DicomModule GetModule(ResourceType type); - - const char* GetDicomSpecificCharacterSet(Encoding encoding); - - HttpStatus ConvertErrorCodeToHttpStatus(ErrorCode error); - - bool IsUserContentType(FileContentType type); - - bool IsBinaryValueRepresentation(ValueRepresentation vr); - - Encoding GetDefaultDicomEncoding(); - - void SetDefaultDicomEncoding(Encoding encoding); - - const char* GetTransferSyntaxUid(DicomTransferSyntax syntax); - - bool IsRetiredTransferSyntax(DicomTransferSyntax syntax); - - bool LookupTransferSyntax(DicomTransferSyntax& target, - const std::string& uid); -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations_TransferSyntaxes.impl.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations_TransferSyntaxes.impl.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations_TransferSyntaxes.impl.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Enumerations_TransferSyntaxes.impl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,566 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -// This file is autogenerated by "../Resources/GenerateTransferSyntaxes.py" - -namespace Orthanc -{ - const char* GetTransferSyntaxUid(DicomTransferSyntax syntax) - { - switch (syntax) - { - case DicomTransferSyntax_LittleEndianImplicit: - return "1.2.840.10008.1.2"; - - case DicomTransferSyntax_LittleEndianExplicit: - return "1.2.840.10008.1.2.1"; - - case DicomTransferSyntax_DeflatedLittleEndianExplicit: - return "1.2.840.10008.1.2.1.99"; - - case DicomTransferSyntax_BigEndianExplicit: - return "1.2.840.10008.1.2.2"; - - case DicomTransferSyntax_JPEGProcess1: - return "1.2.840.10008.1.2.4.50"; - - case DicomTransferSyntax_JPEGProcess2_4: - return "1.2.840.10008.1.2.4.51"; - - case DicomTransferSyntax_JPEGProcess3_5: - return "1.2.840.10008.1.2.4.52"; - - case DicomTransferSyntax_JPEGProcess6_8: - return "1.2.840.10008.1.2.4.53"; - - case DicomTransferSyntax_JPEGProcess7_9: - return "1.2.840.10008.1.2.4.54"; - - case DicomTransferSyntax_JPEGProcess10_12: - return "1.2.840.10008.1.2.4.55"; - - case DicomTransferSyntax_JPEGProcess11_13: - return "1.2.840.10008.1.2.4.56"; - - case DicomTransferSyntax_JPEGProcess14: - return "1.2.840.10008.1.2.4.57"; - - case DicomTransferSyntax_JPEGProcess15: - return "1.2.840.10008.1.2.4.58"; - - case DicomTransferSyntax_JPEGProcess16_18: - return "1.2.840.10008.1.2.4.59"; - - case DicomTransferSyntax_JPEGProcess17_19: - return "1.2.840.10008.1.2.4.60"; - - case DicomTransferSyntax_JPEGProcess20_22: - return "1.2.840.10008.1.2.4.61"; - - case DicomTransferSyntax_JPEGProcess21_23: - return "1.2.840.10008.1.2.4.62"; - - case DicomTransferSyntax_JPEGProcess24_26: - return "1.2.840.10008.1.2.4.63"; - - case DicomTransferSyntax_JPEGProcess25_27: - return "1.2.840.10008.1.2.4.64"; - - case DicomTransferSyntax_JPEGProcess28: - return "1.2.840.10008.1.2.4.65"; - - case DicomTransferSyntax_JPEGProcess29: - return "1.2.840.10008.1.2.4.66"; - - case DicomTransferSyntax_JPEGProcess14SV1: - return "1.2.840.10008.1.2.4.70"; - - case DicomTransferSyntax_JPEGLSLossless: - return "1.2.840.10008.1.2.4.80"; - - case DicomTransferSyntax_JPEGLSLossy: - return "1.2.840.10008.1.2.4.81"; - - case DicomTransferSyntax_JPEG2000LosslessOnly: - return "1.2.840.10008.1.2.4.90"; - - case DicomTransferSyntax_JPEG2000: - return "1.2.840.10008.1.2.4.91"; - - case DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly: - return "1.2.840.10008.1.2.4.92"; - - case DicomTransferSyntax_JPEG2000Multicomponent: - return "1.2.840.10008.1.2.4.93"; - - case DicomTransferSyntax_JPIPReferenced: - return "1.2.840.10008.1.2.4.94"; - - case DicomTransferSyntax_JPIPReferencedDeflate: - return "1.2.840.10008.1.2.4.95"; - - case DicomTransferSyntax_MPEG2MainProfileAtMainLevel: - return "1.2.840.10008.1.2.4.100"; - - case DicomTransferSyntax_MPEG2MainProfileAtHighLevel: - return "1.2.840.10008.1.2.4.101"; - - case DicomTransferSyntax_MPEG4HighProfileLevel4_1: - return "1.2.840.10008.1.2.4.102"; - - case DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1: - return "1.2.840.10008.1.2.4.103"; - - case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo: - return "1.2.840.10008.1.2.4.104"; - - case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo: - return "1.2.840.10008.1.2.4.105"; - - case DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2: - return "1.2.840.10008.1.2.4.106"; - - case DicomTransferSyntax_HEVCMainProfileLevel5_1: - return "1.2.840.10008.1.2.4.107"; - - case DicomTransferSyntax_HEVCMain10ProfileLevel5_1: - return "1.2.840.10008.1.2.4.108"; - - case DicomTransferSyntax_RLELossless: - return "1.2.840.10008.1.2.5"; - - case DicomTransferSyntax_RFC2557MimeEncapsulation: - return "1.2.840.10008.1.2.6.1"; - - case DicomTransferSyntax_XML: - return "1.2.840.10008.1.2.6.2"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool IsRetiredTransferSyntax(DicomTransferSyntax syntax) - { - switch (syntax) - { - case DicomTransferSyntax_LittleEndianImplicit: - return false; - - case DicomTransferSyntax_LittleEndianExplicit: - return false; - - case DicomTransferSyntax_DeflatedLittleEndianExplicit: - return false; - - case DicomTransferSyntax_BigEndianExplicit: - return false; - - case DicomTransferSyntax_JPEGProcess1: - return false; - - case DicomTransferSyntax_JPEGProcess2_4: - return false; - - case DicomTransferSyntax_JPEGProcess3_5: - return true; - - case DicomTransferSyntax_JPEGProcess6_8: - return true; - - case DicomTransferSyntax_JPEGProcess7_9: - return true; - - case DicomTransferSyntax_JPEGProcess10_12: - return true; - - case DicomTransferSyntax_JPEGProcess11_13: - return true; - - case DicomTransferSyntax_JPEGProcess14: - return false; - - case DicomTransferSyntax_JPEGProcess15: - return true; - - case DicomTransferSyntax_JPEGProcess16_18: - return true; - - case DicomTransferSyntax_JPEGProcess17_19: - return true; - - case DicomTransferSyntax_JPEGProcess20_22: - return true; - - case DicomTransferSyntax_JPEGProcess21_23: - return true; - - case DicomTransferSyntax_JPEGProcess24_26: - return true; - - case DicomTransferSyntax_JPEGProcess25_27: - return true; - - case DicomTransferSyntax_JPEGProcess28: - return true; - - case DicomTransferSyntax_JPEGProcess29: - return true; - - case DicomTransferSyntax_JPEGProcess14SV1: - return false; - - case DicomTransferSyntax_JPEGLSLossless: - return false; - - case DicomTransferSyntax_JPEGLSLossy: - return false; - - case DicomTransferSyntax_JPEG2000LosslessOnly: - return false; - - case DicomTransferSyntax_JPEG2000: - return false; - - case DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly: - return false; - - case DicomTransferSyntax_JPEG2000Multicomponent: - return false; - - case DicomTransferSyntax_JPIPReferenced: - return false; - - case DicomTransferSyntax_JPIPReferencedDeflate: - return false; - - case DicomTransferSyntax_MPEG2MainProfileAtMainLevel: - return false; - - case DicomTransferSyntax_MPEG2MainProfileAtHighLevel: - return false; - - case DicomTransferSyntax_MPEG4HighProfileLevel4_1: - return false; - - case DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1: - return false; - - case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo: - return false; - - case DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo: - return false; - - case DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2: - return false; - - case DicomTransferSyntax_HEVCMainProfileLevel5_1: - return false; - - case DicomTransferSyntax_HEVCMain10ProfileLevel5_1: - return false; - - case DicomTransferSyntax_RLELossless: - return false; - - case DicomTransferSyntax_RFC2557MimeEncapsulation: - return true; - - case DicomTransferSyntax_XML: - return true; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool LookupTransferSyntax(DicomTransferSyntax& target, - const std::string& uid) - { - if (uid == "1.2.840.10008.1.2") - { - target = DicomTransferSyntax_LittleEndianImplicit; - return true; - } - - if (uid == "1.2.840.10008.1.2.1") - { - target = DicomTransferSyntax_LittleEndianExplicit; - return true; - } - - if (uid == "1.2.840.10008.1.2.1.99") - { - target = DicomTransferSyntax_DeflatedLittleEndianExplicit; - return true; - } - - if (uid == "1.2.840.10008.1.2.2") - { - target = DicomTransferSyntax_BigEndianExplicit; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.50") - { - target = DicomTransferSyntax_JPEGProcess1; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.51") - { - target = DicomTransferSyntax_JPEGProcess2_4; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.52") - { - target = DicomTransferSyntax_JPEGProcess3_5; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.53") - { - target = DicomTransferSyntax_JPEGProcess6_8; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.54") - { - target = DicomTransferSyntax_JPEGProcess7_9; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.55") - { - target = DicomTransferSyntax_JPEGProcess10_12; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.56") - { - target = DicomTransferSyntax_JPEGProcess11_13; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.57") - { - target = DicomTransferSyntax_JPEGProcess14; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.58") - { - target = DicomTransferSyntax_JPEGProcess15; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.59") - { - target = DicomTransferSyntax_JPEGProcess16_18; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.60") - { - target = DicomTransferSyntax_JPEGProcess17_19; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.61") - { - target = DicomTransferSyntax_JPEGProcess20_22; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.62") - { - target = DicomTransferSyntax_JPEGProcess21_23; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.63") - { - target = DicomTransferSyntax_JPEGProcess24_26; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.64") - { - target = DicomTransferSyntax_JPEGProcess25_27; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.65") - { - target = DicomTransferSyntax_JPEGProcess28; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.66") - { - target = DicomTransferSyntax_JPEGProcess29; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.70") - { - target = DicomTransferSyntax_JPEGProcess14SV1; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.80") - { - target = DicomTransferSyntax_JPEGLSLossless; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.81") - { - target = DicomTransferSyntax_JPEGLSLossy; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.90") - { - target = DicomTransferSyntax_JPEG2000LosslessOnly; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.91") - { - target = DicomTransferSyntax_JPEG2000; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.92") - { - target = DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.93") - { - target = DicomTransferSyntax_JPEG2000Multicomponent; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.94") - { - target = DicomTransferSyntax_JPIPReferenced; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.95") - { - target = DicomTransferSyntax_JPIPReferencedDeflate; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.100") - { - target = DicomTransferSyntax_MPEG2MainProfileAtMainLevel; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.101") - { - target = DicomTransferSyntax_MPEG2MainProfileAtHighLevel; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.102") - { - target = DicomTransferSyntax_MPEG4HighProfileLevel4_1; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.103") - { - target = DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.104") - { - target = DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.105") - { - target = DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.106") - { - target = DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.107") - { - target = DicomTransferSyntax_HEVCMainProfileLevel5_1; - return true; - } - - if (uid == "1.2.840.10008.1.2.4.108") - { - target = DicomTransferSyntax_HEVCMain10ProfileLevel5_1; - return true; - } - - if (uid == "1.2.840.10008.1.2.5") - { - target = DicomTransferSyntax_RLELossless; - return true; - } - - if (uid == "1.2.840.10008.1.2.6.1") - { - target = DicomTransferSyntax_RFC2557MimeEncapsulation; - return true; - } - - if (uid == "1.2.840.10008.1.2.6.2") - { - target = DicomTransferSyntax_XML; - return true; - } - - return false; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "FileBuffer.h" - -#include "TemporaryFile.h" -#include "OrthancException.h" - -#include - - -namespace Orthanc -{ - class FileBuffer::PImpl - { - private: - TemporaryFile file_; - boost::filesystem::ofstream stream_; - bool isWriting_; - - public: - PImpl() : - isWriting_(true) - { - stream_.open(file_.GetPath(), std::ofstream::out | std::ofstream::binary); - if (!stream_.good()) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - } - - ~PImpl() - { - if (isWriting_) - { - stream_.close(); - } - } - - void Append(const char* buffer, - size_t size) - { - if (!isWriting_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (size > 0) - { - stream_.write(buffer, size); - if (!stream_.good()) - { - stream_.close(); - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - } - - void Read(std::string& target) - { - if (isWriting_) - { - stream_.close(); - isWriting_ = false; - } - - file_.Read(target); - } - }; - - - FileBuffer::FileBuffer() : - pimpl_(new PImpl) - { - } - - - void FileBuffer::Append(const char* buffer, - size_t size) - { - assert(pimpl_.get() != NULL); - pimpl_->Append(buffer, size); - } - - - void FileBuffer::Read(std::string& target) - { - assert(pimpl_.get() != NULL); - pimpl_->Read(target); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileBuffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The namespace SystemToolbox cannot be used in sandboxed environments -#endif - -#include -#include - - -namespace Orthanc -{ - class FileBuffer : public boost::noncopyable - { - private: - class PImpl; - boost::shared_ptr pimpl_; - - public: - FileBuffer(); - - void Append(const char* buffer, - size_t size); - - void Read(std::string& target); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FileInfo.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FileInfo.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FileInfo.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FileInfo.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,132 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include -#include "../Enumerations.h" - -namespace Orthanc -{ - struct FileInfo - { - private: - std::string uuid_; - FileContentType contentType_; - - uint64_t uncompressedSize_; - std::string uncompressedMD5_; - - CompressionType compressionType_; - uint64_t compressedSize_; - std::string compressedMD5_; - - public: - FileInfo() - { - } - - /** - * Constructor for an uncompressed attachment. - **/ - FileInfo(const std::string& uuid, - FileContentType contentType, - uint64_t size, - const std::string& md5) : - uuid_(uuid), - contentType_(contentType), - uncompressedSize_(size), - uncompressedMD5_(md5), - compressionType_(CompressionType_None), - compressedSize_(size), - compressedMD5_(md5) - { - } - - /** - * Constructor for a compressed attachment. - **/ - FileInfo(const std::string& uuid, - FileContentType contentType, - uint64_t uncompressedSize, - const std::string& uncompressedMD5, - CompressionType compressionType, - uint64_t compressedSize, - const std::string& compressedMD5) : - uuid_(uuid), - contentType_(contentType), - uncompressedSize_(uncompressedSize), - uncompressedMD5_(uncompressedMD5), - compressionType_(compressionType), - compressedSize_(compressedSize), - compressedMD5_(compressedMD5) - { - } - - const std::string& GetUuid() const - { - return uuid_; - } - - FileContentType GetContentType() const - { - return contentType_; - } - - uint64_t GetUncompressedSize() const - { - return uncompressedSize_; - } - - CompressionType GetCompressionType() const - { - return compressionType_; - } - - uint64_t GetCompressedSize() const - { - return compressedSize_; - } - - const std::string& GetCompressedMD5() const - { - return compressedMD5_; - } - - const std::string& GetUncompressedMD5() const - { - return uncompressedMD5_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,274 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "FilesystemStorage.h" - -// http://stackoverflow.com/questions/1576272/storing-large-number-of-files-in-file-system -// http://stackoverflow.com/questions/446358/storing-a-large-number-of-images - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "../SystemToolbox.h" - -#include - - -static std::string ToString(const boost::filesystem::path& p) -{ -#if BOOST_HAS_FILESYSTEM_V3 == 1 - return p.filename().string(); -#else - return p.filename(); -#endif -} - - -namespace Orthanc -{ - boost::filesystem::path FilesystemStorage::GetPath(const std::string& uuid) const - { - namespace fs = boost::filesystem; - - if (!Toolbox::IsUuid(uuid)) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - fs::path path = root_; - - path /= std::string(&uuid[0], &uuid[2]); - path /= std::string(&uuid[2], &uuid[4]); - path /= uuid; - -#if BOOST_HAS_FILESYSTEM_V3 == 1 - path.make_preferred(); -#endif - - return path; - } - - FilesystemStorage::FilesystemStorage(std::string root) - { - //root_ = boost::filesystem::absolute(root).string(); - root_ = root; - - SystemToolbox::MakeDirectory(root); - } - - - - static const char* GetDescriptionInternal(FileContentType content) - { - // This function is for logging only (internal use), a more - // fully-featured version is available in ServerEnumerations.cpp - switch (content) - { - case FileContentType_Unknown: - return "Unknown"; - - case FileContentType_Dicom: - return "DICOM"; - - case FileContentType_DicomAsJson: - return "JSON summary of DICOM"; - - default: - return "User-defined"; - } - } - - - void FilesystemStorage::Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type) - { - LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) - << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)"; - - boost::filesystem::path path; - - path = GetPath(uuid); - - if (boost::filesystem::exists(path)) - { - // Extremely unlikely case: This Uuid has already been created - // in the past. - throw OrthancException(ErrorCode_InternalError); - } - - if (boost::filesystem::exists(path.parent_path())) - { - if (!boost::filesystem::is_directory(path.parent_path())) - { - throw OrthancException(ErrorCode_DirectoryOverFile); - } - } - else - { - if (!boost::filesystem::create_directories(path.parent_path())) - { - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - - SystemToolbox::WriteFile(content, size, path.string()); - } - - - void FilesystemStorage::Read(std::string& content, - const std::string& uuid, - FileContentType type) - { - LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type) - << "\" content type"; - - content.clear(); - SystemToolbox::ReadFile(content, GetPath(uuid).string()); - } - - - uintmax_t FilesystemStorage::GetSize(const std::string& uuid) const - { - boost::filesystem::path path = GetPath(uuid); - return boost::filesystem::file_size(path); - } - - - - void FilesystemStorage::ListAllFiles(std::set& result) const - { - namespace fs = boost::filesystem; - - result.clear(); - - if (fs::exists(root_) && fs::is_directory(root_)) - { - for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current) - { - if (SystemToolbox::IsRegularFile(current->path().string())) - { - try - { - fs::path d = current->path(); - std::string uuid = ToString(d); - if (Toolbox::IsUuid(uuid)) - { - fs::path p0 = d.parent_path().parent_path().parent_path(); - std::string p1 = ToString(d.parent_path().parent_path()); - std::string p2 = ToString(d.parent_path()); - if (p1.length() == 2 && - p2.length() == 2 && - p1 == uuid.substr(0, 2) && - p2 == uuid.substr(2, 2) && - p0 == root_) - { - result.insert(uuid); - } - } - } - catch (fs::filesystem_error&) - { - } - } - } - } - } - - - void FilesystemStorage::Clear() - { - namespace fs = boost::filesystem; - typedef std::set List; - - List result; - ListAllFiles(result); - - for (List::const_iterator it = result.begin(); it != result.end(); ++it) - { - Remove(*it, FileContentType_Unknown /*ignored in this class*/); - } - } - - - void FilesystemStorage::Remove(const std::string& uuid, - FileContentType type) - { - LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast(type); - - namespace fs = boost::filesystem; - - fs::path p = GetPath(uuid); - - try - { - fs::remove(p); - } - catch (...) - { - // Ignore the error - } - - // Remove the two parent directories, ignoring the error code if - // these directories are not empty - - try - { -#if BOOST_HAS_FILESYSTEM_V3 == 1 - boost::system::error_code err; - fs::remove(p.parent_path(), err); - fs::remove(p.parent_path().parent_path(), err); -#else - fs::remove(p.parent_path()); - fs::remove(p.parent_path().parent_path()); -#endif - } - catch (...) - { - // Ignore the error - } - } - - - uintmax_t FilesystemStorage::GetCapacity() const - { - return boost::filesystem::space(root_).capacity; - } - - uintmax_t FilesystemStorage::GetAvailableSpace() const - { - return boost::filesystem::space(root_).available; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/FilesystemStorage.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The class FilesystemStorage cannot be used in sandboxed environments -#endif - -#include "IStorageArea.h" - -#include -#include -#include - -namespace Orthanc -{ - class FilesystemStorage : public IStorageArea - { - // TODO REMOVE THIS - friend class FilesystemHttpSender; - friend class FileStorageAccessor; - - private: - boost::filesystem::path root_; - - boost::filesystem::path GetPath(const std::string& uuid) const; - - public: - explicit FilesystemStorage(std::string root); - - virtual void Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type); - - virtual void Read(std::string& content, - const std::string& uuid, - FileContentType type); - - virtual void Remove(const std::string& uuid, - FileContentType type); - - void ListAllFiles(std::set& result) const; - - uintmax_t GetSize(const std::string& uuid) const; - - void Clear(); - - uintmax_t GetCapacity() const; - - uintmax_t GetAvailableSpace() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/IStorageArea.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/IStorageArea.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/IStorageArea.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/IStorageArea.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include -#include - -namespace Orthanc -{ - class IStorageArea : public boost::noncopyable - { - public: - virtual ~IStorageArea() - { - } - - virtual void Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type) = 0; - - virtual void Read(std::string& content, - const std::string& uuid, - FileContentType type) = 0; - - virtual void Remove(const std::string& uuid, - FileContentType type) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,128 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "MemoryStorageArea.h" - -#include "../OrthancException.h" -#include "../Logging.h" - -namespace Orthanc -{ - MemoryStorageArea::~MemoryStorageArea() - { - for (Content::iterator it = content_.begin(); it != content_.end(); ++it) - { - if (it->second != NULL) - { - delete it->second; - } - } - } - - void MemoryStorageArea::Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type) - { - LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << static_cast(type) - << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)"; - - boost::mutex::scoped_lock lock(mutex_); - - if (size != 0 && - content == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else if (content_.find(uuid) != content_.end()) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - content_[uuid] = new std::string(reinterpret_cast(content), size); - } - } - - - void MemoryStorageArea::Read(std::string& content, - const std::string& uuid, - FileContentType type) - { - LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" - << static_cast(type) << "\" content type"; - - boost::mutex::scoped_lock lock(mutex_); - - Content::const_iterator found = content_.find(uuid); - - if (found == content_.end()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - else if (found->second == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - content.assign(*found->second); - } - } - - - void MemoryStorageArea::Remove(const std::string& uuid, - FileContentType type) - { - LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast(type); - - boost::mutex::scoped_lock lock(mutex_); - - Content::iterator found = content_.find(uuid); - - if (found == content_.end()) - { - // Ignore second removal - } - else if (found->second == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - delete found->second; - content_.erase(found); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/MemoryStorageArea.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IStorageArea.h" - -#include -#include - -namespace Orthanc -{ - class MemoryStorageArea : public IStorageArea - { - private: - typedef std::map Content; - - boost::mutex mutex_; - Content content_; - - public: - virtual ~MemoryStorageArea(); - - virtual void Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type); - - virtual void Read(std::string& content, - const std::string& uuid, - FileContentType type); - - virtual void Remove(const std::string& uuid, - FileContentType type); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,246 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "StorageAccessor.h" - -#include "../Compatibility.h" -#include "../Compression/ZlibCompressor.h" -#include "../MetricsRegistry.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 -# include "../HttpServer/HttpStreamTranscoder.h" -#endif - - -static const std::string METRICS_CREATE = "orthanc_storage_create_duration_ms"; -static const std::string METRICS_READ = "orthanc_storage_read_duration_ms"; -static const std::string METRICS_REMOVE = "orthanc_storage_remove_duration_ms"; - - -namespace Orthanc -{ - class StorageAccessor::MetricsTimer : public boost::noncopyable - { - private: - std::unique_ptr timer_; - - public: - MetricsTimer(StorageAccessor& that, - const std::string& name) - { - if (that.metrics_ != NULL) - { - timer_.reset(new MetricsRegistry::Timer(*that.metrics_, name)); - } - } - }; - - - FileInfo StorageAccessor::Write(const void* data, - size_t size, - FileContentType type, - CompressionType compression, - bool storeMd5) - { - std::string uuid = Toolbox::GenerateUuid(); - - std::string md5; - - if (storeMd5) - { - Toolbox::ComputeMD5(md5, data, size); - } - - switch (compression) - { - case CompressionType_None: - { - MetricsTimer timer(*this, METRICS_CREATE); - - area_.Create(uuid, data, size, type); - return FileInfo(uuid, type, size, md5); - } - - case CompressionType_ZlibWithSize: - { - ZlibCompressor zlib; - - std::string compressed; - zlib.Compress(compressed, data, size); - - std::string compressedMD5; - - if (storeMd5) - { - Toolbox::ComputeMD5(compressedMD5, compressed); - } - - { - MetricsTimer timer(*this, METRICS_CREATE); - - if (compressed.size() > 0) - { - area_.Create(uuid, &compressed[0], compressed.size(), type); - } - else - { - area_.Create(uuid, NULL, 0, type); - } - } - - return FileInfo(uuid, type, size, md5, - CompressionType_ZlibWithSize, compressed.size(), compressedMD5); - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void StorageAccessor::Read(std::string& content, - const FileInfo& info) - { - switch (info.GetCompressionType()) - { - case CompressionType_None: - { - MetricsTimer timer(*this, METRICS_READ); - area_.Read(content, info.GetUuid(), info.GetContentType()); - break; - } - - case CompressionType_ZlibWithSize: - { - ZlibCompressor zlib; - - std::string compressed; - - { - MetricsTimer timer(*this, METRICS_READ); - area_.Read(compressed, info.GetUuid(), info.GetContentType()); - } - - IBufferCompressor::Uncompress(content, zlib, compressed); - break; - } - - default: - { - throw OrthancException(ErrorCode_NotImplemented); - } - } - - // TODO Check the validity of the uncompressed MD5? - } - - - void StorageAccessor::ReadRaw(std::string& content, - const FileInfo& info) - { - MetricsTimer timer(*this, METRICS_READ); - area_.Read(content, info.GetUuid(), info.GetContentType()); - } - - - void StorageAccessor::Remove(const std::string& fileUuid, - FileContentType type) - { - MetricsTimer timer(*this, METRICS_REMOVE); - area_.Remove(fileUuid, type); - } - - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void StorageAccessor::SetupSender(BufferHttpSender& sender, - const FileInfo& info, - const std::string& mime) - { - { - MetricsTimer timer(*this, METRICS_READ); - area_.Read(sender.GetBuffer(), info.GetUuid(), info.GetContentType()); - } - - sender.SetContentType(mime); - - const char* extension; - switch (info.GetContentType()) - { - case FileContentType_Dicom: - extension = ".dcm"; - break; - - case FileContentType_DicomAsJson: - extension = ".json"; - break; - - default: - // Non-standard content type - extension = ""; - } - - sender.SetContentFilename(info.GetUuid() + std::string(extension)); - } -#endif - - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void StorageAccessor::AnswerFile(HttpOutput& output, - const FileInfo& info, - const std::string& mime) - { - BufferHttpSender sender; - SetupSender(sender, info, mime); - - HttpStreamTranscoder transcoder(sender, info.GetCompressionType()); - output.Answer(transcoder); - } -#endif - - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void StorageAccessor::AnswerFile(RestApiOutput& output, - const FileInfo& info, - const std::string& mime) - { - BufferHttpSender sender; - SetupSender(sender, info, mime); - - HttpStreamTranscoder transcoder(sender, info.GetCompressionType()); - output.AnswerStream(transcoder); - } -#endif -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/FileStorage/StorageAccessor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,155 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The class StorageAccessor cannot be used in sandboxed environments -#endif - -#if !defined(ORTHANC_ENABLE_CIVETWEB) -# error Macro ORTHANC_ENABLE_CIVETWEB must be defined to use this file -#endif - -#if !defined(ORTHANC_ENABLE_MONGOOSE) -# error Macro ORTHANC_ENABLE_MONGOOSE must be defined to use this file -#endif - -#include "IStorageArea.h" -#include "FileInfo.h" - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 -# include "../HttpServer/BufferHttpSender.h" -# include "../RestApi/RestApiOutput.h" -#endif - -#include -#include -#include -#include - -namespace Orthanc -{ - class MetricsRegistry; - - /** - * This class handles the compression/decompression of the raw files - * contained in the storage area, and monitors timing metrics (if - * enabled). - **/ - class StorageAccessor : boost::noncopyable - { - private: - class MetricsTimer; - - IStorageArea& area_; - MetricsRegistry* metrics_; - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void SetupSender(BufferHttpSender& sender, - const FileInfo& info, - const std::string& mime); -#endif - - public: - StorageAccessor(IStorageArea& area) : - area_(area), - metrics_(NULL) - { - } - - StorageAccessor(IStorageArea& area, - MetricsRegistry& metrics) : - area_(area), - metrics_(&metrics) - { - } - - FileInfo Write(const void* data, - size_t size, - FileContentType type, - CompressionType compression, - bool storeMd5); - - FileInfo Write(const std::string& data, - FileContentType type, - CompressionType compression, - bool storeMd5) - { - return Write((data.size() == 0 ? NULL : data.c_str()), - data.size(), type, compression, storeMd5); - } - - void Read(std::string& content, - const FileInfo& info); - - void ReadRaw(std::string& content, - const FileInfo& info); - - void Remove(const std::string& fileUuid, - FileContentType type); - - void Remove(const FileInfo& info) - { - Remove(info.GetUuid(), info.GetContentType()); - } - -#if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 - void AnswerFile(HttpOutput& output, - const FileInfo& info, - MimeType mime) - { - AnswerFile(output, info, EnumerationToString(mime)); - } - - void AnswerFile(HttpOutput& output, - const FileInfo& info, - const std::string& mime); - - void AnswerFile(RestApiOutput& output, - const FileInfo& info, - MimeType mime) - { - AnswerFile(output, info, EnumerationToString(mime)); - } - - void AnswerFile(RestApiOutput& output, - const FileInfo& info, - const std::string& mime); -#endif - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1214 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "HttpClient.h" - -#include "Toolbox.h" -#include "OrthancException.h" -#include "Logging.h" -#include "ChunkedBuffer.h" -#include "SystemToolbox.h" - -#include -#include -#include -#include - -// Default timeout = 60 seconds (in Orthanc <= 1.5.6, it was 10 seconds) -static const unsigned int DEFAULT_HTTP_TIMEOUT = 60; - - -#if ORTHANC_ENABLE_PKCS11 == 1 -# include "Pkcs11.h" -#endif - - -extern "C" -{ - static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status) - { - if (code == CURLE_OK) - { - code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status); - return code; - } - else - { - LOG(ERROR) << "Error code " << static_cast(code) - << " in libcurl: " << curl_easy_strerror(code); - *status = 0; - return code; - } - } -} - -// This is a dummy wrapper function to suppress any OpenSSL-related -// problem in valgrind. Inlining is prevented. -#if defined(__GNUC__) || defined(__clang__) - __attribute__((noinline)) -#endif -static CURLcode OrthancHttpClientPerformSSL(CURL* curl, long* status) -{ -#if ORTHANC_ENABLE_SSL == 1 - return GetHttpStatus(curl_easy_perform(curl), curl, status); -#else - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, - "Orthanc was compiled without SSL support, " - "cannot make HTTPS request"); -#endif -} - - - -namespace Orthanc -{ - static CURLcode CheckCode(CURLcode code) - { - if (code == CURLE_NOT_BUILT_IN) - { - throw OrthancException(ErrorCode_InternalError, - "Your libcurl does not contain a required feature, " - "please recompile Orthanc with -DUSE_SYSTEM_CURL=OFF"); - } - - if (code != CURLE_OK) - { - throw OrthancException(ErrorCode_NetworkProtocol, - "libCURL error: " + std::string(curl_easy_strerror(code))); - } - - return code; - } - - - // RAII pattern around a "curl_slist" - class HttpClient::CurlHeaders : public boost::noncopyable - { - private: - struct curl_slist *content_; - bool isChunkedTransfer_; - bool hasExpect_; - - public: - CurlHeaders() : - content_(NULL), - isChunkedTransfer_(false), - hasExpect_(false) - { - } - - CurlHeaders(const HttpClient::HttpHeaders& headers) - { - for (HttpClient::HttpHeaders::const_iterator - it = headers.begin(); it != headers.end(); ++it) - { - AddHeader(it->first, it->second); - } - } - - ~CurlHeaders() - { - Clear(); - } - - bool IsEmpty() const - { - return content_ == NULL; - } - - void Clear() - { - if (content_ != NULL) - { - curl_slist_free_all(content_); - content_ = NULL; - } - - isChunkedTransfer_ = false; - hasExpect_ = false; - } - - void AddHeader(const std::string& key, - const std::string& value) - { - if (boost::iequals(key, "Expect")) - { - hasExpect_ = true; - } - - if (boost::iequals(key, "Transfer-Encoding") && - value == "chunked") - { - isChunkedTransfer_ = true; - } - - std::string item = key + ": " + value; - - struct curl_slist *tmp = curl_slist_append(content_, item.c_str()); - - if (tmp == NULL) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - else - { - content_ = tmp; - } - } - - void Assign(CURL* curl) const - { - CheckCode(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, content_)); - } - - bool HasExpect() const - { - return hasExpect_; - } - - bool IsChunkedTransfer() const - { - return isChunkedTransfer_; - } - }; - - - class HttpClient::CurlRequestBody : public boost::noncopyable - { - private: - HttpClient::IRequestBody* body_; - std::string sourceBuffer_; - size_t sourceBufferTransmittedSize_; - - size_t CallbackInternal(char* curlBuffer, - size_t curlBufferSize) - { - if (body_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (curlBufferSize == 0) - { - throw OrthancException(ErrorCode_InternalError); - } - - // Read chunks from the body stream so as to fill the target buffer - size_t curlBufferFilledSize = 0; - size_t sourceRemainingSize = sourceBuffer_.size() - sourceBufferTransmittedSize_; - bool hasMore = true; - - while (sourceRemainingSize < curlBufferSize && hasMore) - { - if (sourceRemainingSize > 0) - { - // transmit the end of current source buffer - memcpy(curlBuffer + curlBufferFilledSize, - sourceBuffer_.data() + sourceBufferTransmittedSize_, sourceRemainingSize); - - curlBufferFilledSize += sourceRemainingSize; - } - - // start filling a new source buffer - sourceBufferTransmittedSize_ = 0; - sourceBuffer_.clear(); - - hasMore = body_->ReadNextChunk(sourceBuffer_); - - sourceRemainingSize = sourceBuffer_.size(); - } - - if (sourceRemainingSize > 0 && - curlBufferSize > curlBufferFilledSize) - { - size_t s = std::min(sourceRemainingSize, curlBufferSize - curlBufferFilledSize); - - memcpy(curlBuffer + curlBufferFilledSize, - sourceBuffer_.data() + sourceBufferTransmittedSize_, s); - - sourceBufferTransmittedSize_ += s; - curlBufferFilledSize += s; - } - - return curlBufferFilledSize; - } - - public: - CurlRequestBody() : - body_(NULL), - sourceBufferTransmittedSize_(0) - { - } - - void SetBody(HttpClient::IRequestBody& body) - { - body_ = &body; - sourceBufferTransmittedSize_ = 0; - sourceBuffer_.clear(); - } - - void Clear() - { - body_ = NULL; - sourceBufferTransmittedSize_ = 0; - sourceBuffer_.clear(); - } - - bool IsValid() const - { - return body_ != NULL; - } - - static size_t Callback(char *buffer, size_t size, size_t nitems, void *userdata) - { - try - { - assert(userdata != NULL); - return reinterpret_cast(userdata)-> - CallbackInternal(buffer, size * nitems); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while streaming HTTP body: " << e.What(); - return CURL_READFUNC_ABORT; - } - catch (...) - { - LOG(ERROR) << "Native exception while streaming HTTP body"; - return CURL_READFUNC_ABORT; - } - } - }; - - - class HttpClient::CurlAnswer : public boost::noncopyable - { - private: - HttpClient::IAnswer& answer_; - bool headersLowerCase_; - - public: - CurlAnswer(HttpClient::IAnswer& answer, - bool headersLowerCase) : - answer_(answer), - headersLowerCase_(headersLowerCase) - { - } - - static size_t HeaderCallback(void *buffer, size_t size, size_t nmemb, void *userdata) - { - try - { - assert(userdata != NULL); - CurlAnswer& that = *(static_cast(userdata)); - - size_t length = size * nmemb; - if (length == 0) - { - return 0; - } - else - { - std::string s(reinterpret_cast(buffer), length); - std::size_t colon = s.find(':'); - std::size_t eol = s.find("\r\n"); - if (colon != std::string::npos && - eol != std::string::npos) - { - std::string tmp(s.substr(0, colon)); - - if (that.headersLowerCase_) - { - Toolbox::ToLowerCase(tmp); - } - - std::string key = Toolbox::StripSpaces(tmp); - - if (!key.empty()) - { - std::string value = Toolbox::StripSpaces(s.substr(colon + 1, eol)); - that.answer_.AddHeader(key, value); - } - } - - return length; - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while streaming HTTP body: " << e.What(); - return CURL_READFUNC_ABORT; - } - catch (...) - { - LOG(ERROR) << "Native exception while streaming HTTP body"; - return CURL_READFUNC_ABORT; - } - } - - static size_t BodyCallback(void *buffer, size_t size, size_t nmemb, void *userdata) - { - try - { - assert(userdata != NULL); - CurlAnswer& that = *(static_cast(userdata)); - - size_t length = size * nmemb; - if (length == 0) - { - return 0; - } - else - { - that.answer_.AddChunk(buffer, length); - return length; - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while streaming HTTP body: " << e.What(); - return CURL_READFUNC_ABORT; - } - catch (...) - { - LOG(ERROR) << "Native exception while streaming HTTP body"; - return CURL_READFUNC_ABORT; - } - } - }; - - - class HttpClient::DefaultAnswer : public HttpClient::IAnswer - { - private: - ChunkedBuffer answer_; - HttpHeaders* headers_; - - public: - DefaultAnswer() : headers_(NULL) - { - } - - void SetHeaders(HttpHeaders& headers) - { - headers_ = &headers; - headers_->clear(); - } - - void FlattenBody(std::string& target) - { - answer_.Flatten(target); - } - - virtual void AddHeader(const std::string& key, - const std::string& value) - { - if (headers_ != NULL) - { - (*headers_) [key] = value; - } - } - - virtual void AddChunk(const void* data, - size_t size) - { - answer_.AddChunk(data, size); - } - }; - - - class HttpClient::GlobalParameters - { - private: - boost::mutex mutex_; - bool httpsVerifyPeers_; - std::string httpsCACertificates_; - std::string proxy_; - long timeout_; - bool verbose_; - - GlobalParameters() : - httpsVerifyPeers_(true), - timeout_(0), - verbose_(false) - { - } - - public: - // Singleton pattern - static GlobalParameters& GetInstance() - { - static GlobalParameters parameters; - return parameters; - } - - void ConfigureSsl(bool httpsVerifyPeers, - const std::string& httpsCACertificates) - { - boost::mutex::scoped_lock lock(mutex_); - httpsVerifyPeers_ = httpsVerifyPeers; - httpsCACertificates_ = httpsCACertificates; - } - - void GetSslConfiguration(bool& httpsVerifyPeers, - std::string& httpsCACertificates) - { - boost::mutex::scoped_lock lock(mutex_); - httpsVerifyPeers = httpsVerifyPeers_; - httpsCACertificates = httpsCACertificates_; - } - - void SetDefaultProxy(const std::string& proxy) - { - LOG(INFO) << "Setting the default proxy for HTTP client connections: " << proxy; - - { - boost::mutex::scoped_lock lock(mutex_); - proxy_ = proxy; - } - } - - void GetDefaultProxy(std::string& target) - { - boost::mutex::scoped_lock lock(mutex_); - target = proxy_; - } - - void SetDefaultTimeout(long seconds) - { - LOG(INFO) << "Setting the default timeout for HTTP client connections: " << seconds << " seconds"; - - { - boost::mutex::scoped_lock lock(mutex_); - timeout_ = seconds; - } - } - - long GetDefaultTimeout() - { - boost::mutex::scoped_lock lock(mutex_); - return timeout_; - } - -#if ORTHANC_ENABLE_PKCS11 == 1 - bool IsPkcs11Initialized() - { - boost::mutex::scoped_lock lock(mutex_); - return Pkcs11::IsInitialized(); - } - - void InitializePkcs11(const std::string& module, - const std::string& pin, - bool verbose) - { - boost::mutex::scoped_lock lock(mutex_); - Pkcs11::Initialize(module, pin, verbose); - } -#endif - - bool IsDefaultVerbose() const - { - return verbose_; - } - - void SetDefaultVerbose(bool verbose) - { - verbose_ = verbose; - } - }; - - - struct HttpClient::PImpl - { - CURL* curl_; - CurlHeaders defaultPostHeaders_; - CurlHeaders defaultChunkedHeaders_; - CurlHeaders userHeaders_; - CurlRequestBody requestBody_; - }; - - - void HttpClient::ThrowException(HttpStatus status) - { - switch (status) - { - case HttpStatus_400_BadRequest: - throw OrthancException(ErrorCode_BadRequest); - - case HttpStatus_401_Unauthorized: - case HttpStatus_403_Forbidden: - throw OrthancException(ErrorCode_Unauthorized); - - case HttpStatus_404_NotFound: - throw OrthancException(ErrorCode_UnknownResource); - - default: - throw OrthancException(ErrorCode_NetworkProtocol); - } - } - - - /*static int CurlDebugCallback(CURL *handle, - curl_infotype type, - char *data, - size_t size, - void *userptr) - { - switch (type) - { - case CURLINFO_TEXT: - case CURLINFO_HEADER_IN: - case CURLINFO_HEADER_OUT: - case CURLINFO_SSL_DATA_IN: - case CURLINFO_SSL_DATA_OUT: - case CURLINFO_END: - case CURLINFO_DATA_IN: - case CURLINFO_DATA_OUT: - { - std::string s(data, size); - LOG(INFO) << "libcurl: " << s; - break; - } - - default: - break; - } - - return 0; - }*/ - - - void HttpClient::Setup() - { - pimpl_->defaultPostHeaders_.AddHeader("Expect", ""); - pimpl_->defaultChunkedHeaders_.AddHeader("Expect", ""); - pimpl_->defaultChunkedHeaders_.AddHeader("Transfer-Encoding", "chunked"); - - pimpl_->curl_ = curl_easy_init(); - - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERFUNCTION, &CurlAnswer::HeaderCallback)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEFUNCTION, &CurlAnswer::BodyCallback)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADER, 0)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1)); - - // This fixes the "longjmp causes uninitialized stack frame" crash - // that happens on modern Linux versions. - // http://stackoverflow.com/questions/9191668/error-longjmp-causes-uninitialized-stack-frame - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOSIGNAL, 1)); - - url_ = ""; - method_ = HttpMethod_Get; - lastStatus_ = HttpStatus_None; - SetVerbose(GlobalParameters::GetInstance().IsDefaultVerbose()); - timeout_ = GlobalParameters::GetInstance().GetDefaultTimeout(); - GlobalParameters::GetInstance().GetDefaultProxy(proxy_); - GlobalParameters::GetInstance().GetSslConfiguration(verifyPeers_, caCertificates_); - } - - - HttpClient::HttpClient() : - pimpl_(new PImpl), - verifyPeers_(true), - pkcs11Enabled_(false), - headersToLowerCase_(true), - redirectionFollowed_(true) - { - Setup(); - } - - - HttpClient::HttpClient(const WebServiceParameters& service, - const std::string& uri) : - pimpl_(new PImpl), - verifyPeers_(true), - headersToLowerCase_(true), - redirectionFollowed_(true) - { - Setup(); - - if (service.GetUsername().size() != 0 && - service.GetPassword().size() != 0) - { - SetCredentials(service.GetUsername().c_str(), - service.GetPassword().c_str()); - } - - if (!service.GetCertificateFile().empty()) - { - SetClientCertificate(service.GetCertificateFile(), - service.GetCertificateKeyFile(), - service.GetCertificateKeyPassword()); - } - - SetPkcs11Enabled(service.IsPkcs11Enabled()); - - SetUrl(service.GetUrl() + uri); - - for (WebServiceParameters::Dictionary::const_iterator - it = service.GetHttpHeaders().begin(); - it != service.GetHttpHeaders().end(); ++it) - { - AddHeader(it->first, it->second); - } - } - - - HttpClient::~HttpClient() - { - curl_easy_cleanup(pimpl_->curl_); - } - - - void HttpClient::SetBody(const std::string& data) - { - body_ = data; - pimpl_->requestBody_.Clear(); - } - - - void HttpClient::SetBody(IRequestBody& body) - { - body_.clear(); - pimpl_->requestBody_.SetBody(body); - } - - - void HttpClient::ClearBody() - { - body_.clear(); - pimpl_->requestBody_.Clear(); - } - - - void HttpClient::SetVerbose(bool isVerbose) - { - isVerbose_ = isVerbose; - - if (isVerbose_) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_VERBOSE, 1)); - //CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_DEBUGFUNCTION, &CurlDebugCallback)); - } - else - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_VERBOSE, 0)); - } - } - - - void HttpClient::AddHeader(const std::string& key, - const std::string& value) - { - if (key.empty()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - pimpl_->userHeaders_.AddHeader(key, value); - } - } - - - void HttpClient::ClearHeaders() - { - pimpl_->userHeaders_.Clear(); - } - - - bool HttpClient::ApplyInternal(CurlAnswer& answer) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str())); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERDATA, &answer)); - -#if ORTHANC_ENABLE_SSL == 1 - // Setup HTTPS-related options - - if (verifyPeers_) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, caCertificates_.c_str())); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYHOST, 2)); // libcurl default is strict verifyhost - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 1)); - } - else - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYHOST, 0)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 0)); - } -#endif - - // Setup the HTTPS client certificate - if (!clientCertificateFile_.empty() && - pkcs11Enabled_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Cannot enable both client certificates and PKCS#11 authentication"); - } - - if (pkcs11Enabled_) - { -#if ORTHANC_ENABLE_PKCS11 == 1 - if (GlobalParameters::GetInstance().IsPkcs11Initialized()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLENGINE, Pkcs11::GetEngineIdentifier())); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEYTYPE, "ENG")); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "ENG")); - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Cannot use PKCS#11 for a HTTPS request, " - "because it has not been initialized"); - } -#else - throw OrthancException(ErrorCode_InternalError, - "This version of Orthanc is compiled without support for PKCS#11"); -#endif - } - else if (!clientCertificateFile_.empty()) - { -#if ORTHANC_ENABLE_SSL == 1 - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "PEM")); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERT, clientCertificateFile_.c_str())); - - if (!clientCertificateKeyPassword_.empty()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_KEYPASSWD, clientCertificateKeyPassword_.c_str())); - } - - // NB: If no "clientKeyFile_" is provided, the key must be - // prepended to the certificate file - if (!clientCertificateKeyFile_.empty()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEYTYPE, "PEM")); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEY, clientCertificateKeyFile_.c_str())); - } -#else - throw OrthancException(ErrorCode_InternalError, - "This version of Orthanc is compiled without OpenSSL support, " - "cannot use HTTPS client authentication"); -#endif - } - - // Reset the parameters from previous calls to Apply() - pimpl_->userHeaders_.Assign(pimpl_->curl_); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPGET, 0L)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 0L)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 0L)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, NULL)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0L)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PROXY, NULL)); - - if (redirectionFollowed_) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1L)); - } - else - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 0L)); - } - - // Set timeouts - if (timeout_ <= 0) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_TIMEOUT, DEFAULT_HTTP_TIMEOUT)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CONNECTTIMEOUT, DEFAULT_HTTP_TIMEOUT)); - } - else - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_TIMEOUT, timeout_)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CONNECTTIMEOUT, timeout_)); - } - - if (credentials_.size() != 0) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_USERPWD, credentials_.c_str())); - } - - if (proxy_.size() != 0) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PROXY, proxy_.c_str())); - } - - switch (method_) - { - case HttpMethod_Get: - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPGET, 1L)); - break; - - case HttpMethod_Post: - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 1L)); - - break; - - case HttpMethod_Delete: - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 1L)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "DELETE")); - break; - - case HttpMethod_Put: - // http://stackoverflow.com/a/7570281/881731: Don't use - // CURLOPT_PUT if there is a body - - // CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PUT, 1L)); - - curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, "PUT"); /* !!! */ - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - if (method_ == HttpMethod_Post || - method_ == HttpMethod_Put) - { - if (!pimpl_->userHeaders_.IsEmpty() && - !pimpl_->userHeaders_.HasExpect()) - { - LOG(INFO) << "For performance, the HTTP header \"Expect\" should be set to empty string in POST/PUT requests"; - } - - if (pimpl_->requestBody_.IsValid()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_READFUNCTION, CurlRequestBody::Callback)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_READDATA, &pimpl_->requestBody_)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POST, 1L)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, -1L)); - - if (pimpl_->userHeaders_.IsEmpty()) - { - pimpl_->defaultChunkedHeaders_.Assign(pimpl_->curl_); - } - else if (!pimpl_->userHeaders_.IsChunkedTransfer()) - { - LOG(WARNING) << "The HTTP header \"Transfer-Encoding\" must be set to \"chunked\" " - << "if streaming a chunked body in POST/PUT requests"; - } - } - else - { - // Disable possible previous stream transfers - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_READFUNCTION, NULL)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_UPLOAD, 0)); - - if (pimpl_->userHeaders_.IsChunkedTransfer()) - { - LOG(WARNING) << "The HTTP header \"Transfer-Encoding\" must only be set " - << "if streaming a chunked body in POST/PUT requests"; - } - - if (pimpl_->userHeaders_.IsEmpty()) - { - pimpl_->defaultPostHeaders_.Assign(pimpl_->curl_); - } - - if (body_.size() > 0) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, body_.c_str())); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, body_.size())); - } - else - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL)); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0)); - } - } - } - - - // Do the actual request - CURLcode code; - long status = 0; - - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer)); - - const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time(); - - if (boost::starts_with(url_, "https://")) - { - code = OrthancHttpClientPerformSSL(pimpl_->curl_, &status); - } - else - { - code = GetHttpStatus(curl_easy_perform(pimpl_->curl_), pimpl_->curl_, &status); - } - - const boost::posix_time::ptime end = boost::posix_time::microsec_clock::universal_time(); - - LOG(INFO) << "HTTP status code " << status << " in " - << ((end - start).total_milliseconds()) << " ms after " - << EnumerationToString(method_) << " request on: " << url_; - - if (isVerbose_) - { - LOG(INFO) << "cURL status code: " << code; - } - - CheckCode(code); - - if (status == 0) - { - // This corresponds to a call to an inexistent host - lastStatus_ = HttpStatus_500_InternalServerError; - } - else - { - lastStatus_ = static_cast(status); - } - - if (status >= 200 && status < 300) - { - return true; // Success - } - else - { - LOG(ERROR) << "Error in HTTP request, received HTTP status " << status - << " (" << EnumerationToString(lastStatus_) << ")"; - return false; - } - } - - - bool HttpClient::ApplyInternal(std::string& answerBody, - HttpHeaders* answerHeaders) - { - answerBody.clear(); - - DefaultAnswer answer; - - if (answerHeaders != NULL) - { - answer.SetHeaders(*answerHeaders); - } - - CurlAnswer wrapper(answer, headersToLowerCase_); - - if (ApplyInternal(wrapper)) - { - answer.FlattenBody(answerBody); - return true; - } - else - { - return false; - } - } - - - bool HttpClient::ApplyInternal(Json::Value& answerBody, - HttpClient::HttpHeaders* answerHeaders) - { - std::string s; - if (ApplyInternal(s, answerHeaders)) - { - Json::Reader reader; - return reader.parse(s, answerBody); - } - else - { - return false; - } - } - - - void HttpClient::SetCredentials(const char* username, - const char* password) - { - credentials_ = std::string(username) + ":" + std::string(password); - } - - - void HttpClient::ConfigureSsl(bool httpsVerifyPeers, - const std::string& httpsVerifyCertificates) - { -#if ORTHANC_ENABLE_SSL == 1 - if (httpsVerifyPeers) - { - if (httpsVerifyCertificates.empty()) - { - LOG(WARNING) << "No certificates are provided to validate peers, " - << "set \"HttpsCACertificates\" if you need to do HTTPS requests"; - } - else - { - LOG(WARNING) << "HTTPS will use the CA certificates from this file: " << httpsVerifyCertificates; - } - } - else - { - LOG(WARNING) << "The verification of the peers in HTTPS requests is disabled"; - } -#endif - - GlobalParameters::GetInstance().ConfigureSsl(httpsVerifyPeers, httpsVerifyCertificates); - } - - - void HttpClient::GlobalInitialize() - { -#if ORTHANC_ENABLE_SSL == 1 - CheckCode(curl_global_init(CURL_GLOBAL_ALL)); -#else - CheckCode(curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL)); -#endif - } - - - void HttpClient::GlobalFinalize() - { - curl_global_cleanup(); - -#if ORTHANC_ENABLE_PKCS11 == 1 - Pkcs11::Finalize(); -#endif - } - - - void HttpClient::SetDefaultVerbose(bool verbose) - { - GlobalParameters::GetInstance().SetDefaultVerbose(verbose); - } - - - void HttpClient::SetDefaultProxy(const std::string& proxy) - { - GlobalParameters::GetInstance().SetDefaultProxy(proxy); - } - - - void HttpClient::SetDefaultTimeout(long timeout) - { - GlobalParameters::GetInstance().SetDefaultTimeout(timeout); - } - - - bool HttpClient::Apply(IAnswer& answer) - { - CurlAnswer wrapper(answer, headersToLowerCase_); - return ApplyInternal(wrapper); - } - - - void HttpClient::ApplyAndThrowException(IAnswer& answer) - { - CurlAnswer wrapper(answer, headersToLowerCase_); - - if (!ApplyInternal(wrapper)) - { - ThrowException(GetLastStatus()); - } - } - - - void HttpClient::ApplyAndThrowException(std::string& answerBody) - { - if (!Apply(answerBody)) - { - ThrowException(GetLastStatus()); - } - } - - - void HttpClient::ApplyAndThrowException(Json::Value& answerBody) - { - if (!Apply(answerBody)) - { - ThrowException(GetLastStatus()); - } - } - - - void HttpClient::ApplyAndThrowException(std::string& answerBody, - HttpHeaders& answerHeaders) - { - if (!Apply(answerBody, answerHeaders)) - { - ThrowException(GetLastStatus()); - } - } - - - void HttpClient::ApplyAndThrowException(Json::Value& answerBody, - HttpHeaders& answerHeaders) - { - if (!Apply(answerBody, answerHeaders)) - { - ThrowException(GetLastStatus()); - } - } - - - void HttpClient::SetClientCertificate(const std::string& certificateFile, - const std::string& certificateKeyFile, - const std::string& certificateKeyPassword) - { - if (certificateFile.empty()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (!SystemToolbox::IsRegularFile(certificateFile)) - { - throw OrthancException(ErrorCode_InexistentFile, - "Cannot open certificate file: " + certificateFile); - } - - if (!certificateKeyFile.empty() && - !SystemToolbox::IsRegularFile(certificateKeyFile)) - { - throw OrthancException(ErrorCode_InexistentFile, - "Cannot open key file: " + certificateKeyFile); - } - - clientCertificateFile_ = certificateFile; - clientCertificateKeyFile_ = certificateKeyFile; - clientCertificateKeyPassword_ = certificateKeyPassword; - } - - - void HttpClient::InitializePkcs11(const std::string& module, - const std::string& pin, - bool verbose) - { -#if ORTHANC_ENABLE_PKCS11 == 1 - LOG(INFO) << "Initializing PKCS#11 using " << module - << (pin.empty() ? " (no PIN provided)" : " (PIN is provided)"); - GlobalParameters::GetInstance().InitializePkcs11(module, pin, verbose); -#else - throw OrthancException(ErrorCode_InternalError, - "This version of Orthanc is compiled without support for PKCS#11"); -#endif - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpClient.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,332 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "Enumerations.h" -#include "WebServiceParameters.h" - -#include -#include -#include -#include - -#if !defined(ORTHANC_ENABLE_SSL) -# error The macro ORTHANC_ENABLE_SSL must be defined -#endif - -#if !defined(ORTHANC_ENABLE_PKCS11) -# error The macro ORTHANC_ENABLE_PKCS11 must be defined -#endif - - -namespace Orthanc -{ - class HttpClient : public boost::noncopyable - { - public: - typedef std::map HttpHeaders; - - class IRequestBody : public boost::noncopyable - { - public: - virtual ~IRequestBody() - { - } - - virtual bool ReadNextChunk(std::string& chunk) = 0; - }; - - class IAnswer : public boost::noncopyable - { - public: - virtual ~IAnswer() - { - } - - virtual void AddHeader(const std::string& key, - const std::string& value) = 0; - - virtual void AddChunk(const void* data, - size_t size) = 0; - }; - - private: - class CurlHeaders; - class CurlRequestBody; - class CurlAnswer; - class DefaultAnswer; - class GlobalParameters; - - struct PImpl; - boost::shared_ptr pimpl_; - - std::string url_; - std::string credentials_; - HttpMethod method_; - HttpStatus lastStatus_; - std::string body_; // This only makes sense for POST and PUT requests - bool isVerbose_; - long timeout_; - std::string proxy_; - bool verifyPeers_; - std::string caCertificates_; - std::string clientCertificateFile_; - std::string clientCertificateKeyFile_; - std::string clientCertificateKeyPassword_; - bool pkcs11Enabled_; - bool headersToLowerCase_; - bool redirectionFollowed_; - - void Setup(); - - void operator= (const HttpClient&); // Assignment forbidden - HttpClient(const HttpClient& base); // Copy forbidden - - bool ApplyInternal(CurlAnswer& answer); - - bool ApplyInternal(std::string& answerBody, - HttpHeaders* answerHeaders); - - bool ApplyInternal(Json::Value& answerBody, - HttpHeaders* answerHeaders); - - public: - HttpClient(); - - HttpClient(const WebServiceParameters& service, - const std::string& uri); - - ~HttpClient(); - - void SetUrl(const char* url) - { - url_ = std::string(url); - } - - void SetUrl(const std::string& url) - { - url_ = url; - } - - const std::string& GetUrl() const - { - return url_; - } - - void SetMethod(HttpMethod method) - { - method_ = method; - } - - HttpMethod GetMethod() const - { - return method_; - } - - void SetTimeout(long seconds) - { - timeout_ = seconds; - } - - long GetTimeout() const - { - return timeout_; - } - - void SetBody(const std::string& data); - - std::string& GetBody() - { - return body_; - } - - const std::string& GetBody() const - { - return body_; - } - - void SetBody(IRequestBody& body); - - void ClearBody(); - - void SetVerbose(bool isVerbose); - - bool IsVerbose() const - { - return isVerbose_; - } - - void AddHeader(const std::string& key, - const std::string& value); - - void ClearHeaders(); - - bool Apply(IAnswer& answer); - - bool Apply(std::string& answerBody) - { - return ApplyInternal(answerBody, NULL); - } - - bool Apply(Json::Value& answerBody) - { - return ApplyInternal(answerBody, NULL); - } - - bool Apply(std::string& answerBody, - HttpHeaders& answerHeaders) - { - return ApplyInternal(answerBody, &answerHeaders); - } - - bool Apply(Json::Value& answerBody, - HttpHeaders& answerHeaders) - { - return ApplyInternal(answerBody, &answerHeaders); - } - - HttpStatus GetLastStatus() const - { - return lastStatus_; - } - - void SetCredentials(const char* username, - const char* password); - - void SetProxy(const std::string& proxy) - { - proxy_ = proxy; - } - - void SetHttpsVerifyPeers(bool verify) - { - verifyPeers_ = verify; - } - - bool IsHttpsVerifyPeers() const - { - return verifyPeers_; - } - - void SetHttpsCACertificates(const std::string& certificates) - { - caCertificates_ = certificates; - } - - const std::string& GetHttpsCACertificates() const - { - return caCertificates_; - } - - void SetClientCertificate(const std::string& certificateFile, - const std::string& certificateKeyFile, - const std::string& certificateKeyPassword); - - void SetPkcs11Enabled(bool enabled) - { - pkcs11Enabled_ = enabled; - } - - bool IsPkcs11Enabled() const - { - return pkcs11Enabled_; - } - - const std::string& GetClientCertificateFile() const - { - return clientCertificateFile_; - } - - const std::string& GetClientCertificateKeyFile() const - { - return clientCertificateKeyFile_; - } - - const std::string& GetClientCertificateKeyPassword() const - { - return clientCertificateKeyPassword_; - } - - void SetConvertHeadersToLowerCase(bool lowerCase) - { - headersToLowerCase_ = lowerCase; - } - - bool IsConvertHeadersToLowerCase() const - { - return headersToLowerCase_; - } - - void SetRedirectionFollowed(bool follow) - { - redirectionFollowed_ = follow; - } - - bool IsRedirectionFollowed() const - { - return redirectionFollowed_; - } - - static void GlobalInitialize(); - - static void GlobalFinalize(); - - static void InitializePkcs11(const std::string& module, - const std::string& pin, - bool verbose); - - static void ConfigureSsl(bool httpsVerifyPeers, - const std::string& httpsCACertificates); - - static void SetDefaultVerbose(bool verbose); - - static void SetDefaultProxy(const std::string& proxy); - - static void SetDefaultTimeout(long timeout); - - void ApplyAndThrowException(IAnswer& answer); - - void ApplyAndThrowException(std::string& answerBody); - - void ApplyAndThrowException(Json::Value& answerBody); - - void ApplyAndThrowException(std::string& answerBody, - HttpHeaders& answerHeaders); - - void ApplyAndThrowException(Json::Value& answerBody, - HttpHeaders& answerHeaders); - - static void ThrowException(HttpStatus status); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#include "../PrecompiledHeaders.h" -#include "BufferHttpSender.h" - -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - BufferHttpSender::BufferHttpSender() : - position_(0), - chunkSize_(0), - currentChunkSize_(0) - { - } - - - bool BufferHttpSender::ReadNextChunk() - { - assert(position_ + currentChunkSize_ <= buffer_.size()); - - position_ += currentChunkSize_; - - if (position_ == buffer_.size()) - { - return false; - } - else - { - currentChunkSize_ = buffer_.size() - position_; - - if (chunkSize_ != 0 && - currentChunkSize_ > chunkSize_) - { - currentChunkSize_ = chunkSize_; - } - - return true; - } - } - - - const char* BufferHttpSender::GetChunkContent() - { - return buffer_.c_str() + position_; - } - - - size_t BufferHttpSender::GetChunkSize() - { - return currentChunkSize_; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/BufferHttpSender.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include "HttpFileSender.h" - -namespace Orthanc -{ - class BufferHttpSender : public HttpFileSender - { - private: - std::string buffer_; - size_t position_; - size_t chunkSize_; - size_t currentChunkSize_; - - public: - BufferHttpSender(); - - std::string& GetBuffer() - { - return buffer_; - } - - const std::string& GetBuffer() const - { - return buffer_; - } - - // This is for test purpose. If "chunkSize" is set to "0" (the - // default), the entire buffer is consumed at once. - void SetChunkSize(size_t chunkSize) - { - chunkSize_ = chunkSize; - } - - - /** - * Implementation of the IHttpStreamAnswer interface. - **/ - - virtual uint64_t GetContentLength() - { - return buffer_.size(); - } - - virtual bool ReadNextChunk(); - - virtual const char* GetChunkContent(); - - virtual size_t GetChunkSize(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "EmbeddedResourceHttpHandler.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../SystemToolbox.h" -#include "HttpOutput.h" - -#include - - -namespace Orthanc -{ - EmbeddedResourceHttpHandler::EmbeddedResourceHttpHandler( - const std::string& baseUri, - EmbeddedResources::DirectoryResourceId resourceId) - { - Toolbox::SplitUriComponents(baseUri_, baseUri); - resourceId_ = resourceId; - } - - - bool EmbeddedResourceHttpHandler::Handle( - HttpOutput& output, - RequestOrigin /*origin*/, - const char* /*remoteIp*/, - const char* /*username*/, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& arguments, - const void* /*bodyData*/, - size_t /*bodySize*/) - { - if (!Toolbox::IsChildUri(baseUri_, uri)) - { - // This URI is not served by this handler - return false; - } - - if (method != HttpMethod_Get) - { - output.SendMethodNotAllowed("GET"); - return true; - } - - std::string resourcePath = Toolbox::FlattenUri(uri, baseUri_.size()); - MimeType contentType = SystemToolbox::AutodetectMimeType(resourcePath); - - try - { - const void* buffer = EmbeddedResources::GetDirectoryResourceBuffer(resourceId_, resourcePath.c_str()); - size_t size = EmbeddedResources::GetDirectoryResourceSize(resourceId_, resourcePath.c_str()); - - output.SetContentType(contentType); - output.Answer(buffer, size); - } - catch (OrthancException&) - { - LOG(WARNING) << "Unable to find HTTP resource: " << resourcePath; - output.SendStatus(HttpStatus_404_NotFound); - } - - return true; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/EmbeddedResourceHttpHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IHttpHandler.h" - -#include // Autogenerated file -#include - -namespace Orthanc -{ - class EmbeddedResourceHttpHandler : public IHttpHandler - { - private: - UriComponents baseUri_; - EmbeddedResources::DirectoryResourceId resourceId_; - - public: - EmbeddedResourceHttpHandler( - const std::string& baseUri, - EmbeddedResources::DirectoryResourceId resourceId); - - virtual bool CreateChunkedRequestReader(std::unique_ptr& target, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers) - { - return false; - } - - virtual bool Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& arguments, - const void* /*bodyData*/, - size_t /*bodySize*/); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "FilesystemHttpHandler.h" - -#include "../OrthancException.h" -#include "../SystemToolbox.h" -#include "FilesystemHttpSender.h" - -#include - - -namespace Orthanc -{ - struct FilesystemHttpHandler::PImpl - { - UriComponents baseUri_; - boost::filesystem::path root_; - }; - - - - static void OutputDirectoryContent(HttpOutput& output, - const IHttpHandler::Arguments& headers, - const UriComponents& uri, - const boost::filesystem::path& p) - { - namespace fs = boost::filesystem; - - std::string s; - s += ""; - s += " "; - s += "

Subdirectories

"; - s += "
    "; - - if (uri.size() > 0) - { - std::string h = Toolbox::FlattenUri(uri) + "/.."; - s += "
  • ..
  • "; - } - - fs::directory_iterator end; - for (fs::directory_iterator it(p) ; it != end; ++it) - { -#if BOOST_HAS_FILESYSTEM_V3 == 1 - std::string f = it->path().filename().string(); -#else - std::string f = it->path().filename(); -#endif - - std::string h = Toolbox::FlattenUri(uri) + "/" + f; - if (fs::is_directory(it->status())) - s += "
  • " + f + "
  • "; - } - - s += "
"; - s += "

Files

"; - s += "
    "; - - for (fs::directory_iterator it(p) ; it != end; ++it) - { -#if BOOST_HAS_FILESYSTEM_V3 == 1 - std::string f = it->path().filename().string(); -#else - std::string f = it->path().filename(); -#endif - - std::string h = Toolbox::FlattenUri(uri) + "/" + f; - if (SystemToolbox::IsRegularFile(it->path().string())) - { - s += "
  • " + f + "
  • "; - } - } - - s += "
"; - s += " "; - s += ""; - - output.SetContentType(MimeType_Html); - output.Answer(s); - } - - - FilesystemHttpHandler::FilesystemHttpHandler(const std::string& baseUri, - const std::string& root) : pimpl_(new PImpl) - { - Toolbox::SplitUriComponents(pimpl_->baseUri_, baseUri); - pimpl_->root_ = root; - listDirectoryContent_ = false; - - namespace fs = boost::filesystem; - if (!fs::exists(pimpl_->root_) || - !fs::is_directory(pimpl_->root_)) - { - throw OrthancException(ErrorCode_DirectoryExpected); - } - } - - - bool FilesystemHttpHandler::Handle( - HttpOutput& output, - RequestOrigin /*origin*/, - const char* /*remoteIp*/, - const char* /*username*/, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& arguments, - const void* /*bodyData*/, - size_t /*bodySize*/) - { - if (!Toolbox::IsChildUri(pimpl_->baseUri_, uri)) - { - // This URI is not served by this handler - return false; - } - - if (method != HttpMethod_Get) - { - output.SendMethodNotAllowed("GET"); - return true; - } - - namespace fs = boost::filesystem; - - fs::path p = pimpl_->root_; - for (size_t i = pimpl_->baseUri_.size(); i < uri.size(); i++) - { - p /= uri[i]; - } - - if (SystemToolbox::IsRegularFile(p.string())) - { - FilesystemHttpSender sender(p); - sender.SetContentType(SystemToolbox::AutodetectMimeType(p.string())); - output.Answer(sender); // TODO COMPRESSION - } - else if (listDirectoryContent_ && - fs::exists(p) && - fs::is_directory(p)) - { - OutputDirectoryContent(output, headers, uri, p); - } - else - { - output.SendStatus(HttpStatus_404_NotFound); - } - - return true; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IHttpHandler.h" - -#include - -namespace Orthanc -{ - class FilesystemHttpHandler : public IHttpHandler - { - private: - // PImpl idiom to avoid the inclusion of boost::filesystem - // throughout the software - struct PImpl; - boost::shared_ptr pimpl_; - - bool listDirectoryContent_; - - public: - FilesystemHttpHandler(const std::string& baseUri, - const std::string& root); - - virtual bool CreateChunkedRequestReader(std::unique_ptr& target, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers) - { - return false; - } - - virtual bool Handle( - HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& arguments, - const void* /*bodyData*/, - size_t /*bodySize*/); - - bool IsListDirectoryContent() const - { - return listDirectoryContent_; - } - - void SetListDirectoryContent(bool enabled) - { - listDirectoryContent_ = enabled; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#include "../PrecompiledHeaders.h" -#include "FilesystemHttpSender.h" - -#include "../OrthancException.h" - -static const size_t CHUNK_SIZE = 64 * 1024; // Use 64KB chunks - -namespace Orthanc -{ - void FilesystemHttpSender::Initialize(const boost::filesystem::path& path) - { - SetContentFilename(path.filename().string()); - file_.open(path.string().c_str(), std::ifstream::binary); - - if (!file_.is_open()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - file_.seekg(0, file_.end); - size_ = file_.tellg(); - file_.seekg(0, file_.beg); - } - - - bool FilesystemHttpSender::ReadNextChunk() - { - if (chunk_.size() == 0) - { - chunk_.resize(CHUNK_SIZE); - } - - file_.read(&chunk_[0], chunk_.size()); - - if ((file_.flags() & std::istream::failbit) || - file_.gcount() < 0) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - - chunkSize_ = static_cast(file_.gcount()); - - return chunkSize_ > 0; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/FilesystemHttpSender.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include "HttpFileSender.h" -#include "BufferHttpSender.h" -#include "../FileStorage/FilesystemStorage.h" - -#include - -namespace Orthanc -{ - class FilesystemHttpSender : public HttpFileSender - { - private: - std::ifstream file_; - uint64_t size_; - std::string chunk_; - size_t chunkSize_; - - void Initialize(const boost::filesystem::path& path); - - public: - explicit FilesystemHttpSender(const std::string& path) - { - Initialize(path); - } - - explicit FilesystemHttpSender(const boost::filesystem::path& path) - { - Initialize(path); - } - - FilesystemHttpSender(const std::string& path, - MimeType contentType) - { - SetContentType(contentType); - Initialize(path); - } - - FilesystemHttpSender(const FilesystemStorage& storage, - const std::string& uuid) - { - Initialize(storage.GetPath(uuid)); - } - - /** - * Implementation of the IHttpStreamAnswer interface. - **/ - - virtual uint64_t GetContentLength() - { - return size_; - } - - virtual bool ReadNextChunk(); - - virtual const char* GetChunkContent() - { - return chunk_.c_str(); - } - - virtual size_t GetChunkSize() - { - return chunkSize_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,271 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "HttpContentNegociation.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#include - -namespace Orthanc -{ - HttpContentNegociation::Handler::Handler(const std::string& type, - const std::string& subtype, - IHandler& handler) : - type_(type), - subtype_(subtype), - handler_(handler) - { - } - - - bool HttpContentNegociation::Handler::IsMatch(const std::string& type, - const std::string& subtype) const - { - if (type == "*" && subtype == "*") - { - return true; - } - - if (subtype == "*" && type == type_) - { - return true; - } - - return type == type_ && subtype == subtype_; - } - - - struct HttpContentNegociation::Reference : public boost::noncopyable - { - const Handler& handler_; - uint8_t level_; - float quality_; - - Reference(const Handler& handler, - const std::string& type, - const std::string& subtype, - float quality) : - handler_(handler), - quality_(quality) - { - if (type == "*" && subtype == "*") - { - level_ = 0; - } - else if (subtype == "*") - { - level_ = 1; - } - else - { - level_ = 2; - } - } - - bool operator< (const Reference& other) const - { - if (level_ < other.level_) - { - return true; - } - - if (level_ > other.level_) - { - return false; - } - - return quality_ < other.quality_; - } - }; - - - bool HttpContentNegociation::SplitPair(std::string& first /* out */, - std::string& second /* out */, - const std::string& source, - char separator) - { - size_t pos = source.find(separator); - - if (pos == std::string::npos) - { - return false; - } - else - { - first = Toolbox::StripSpaces(source.substr(0, pos)); - second = Toolbox::StripSpaces(source.substr(pos + 1)); - return true; - } - } - - - float HttpContentNegociation::GetQuality(const Tokens& parameters) - { - for (size_t i = 1; i < parameters.size(); i++) - { - std::string key, value; - if (SplitPair(key, value, parameters[i], '=') && - key == "q") - { - float quality; - bool ok = false; - - try - { - quality = boost::lexical_cast(value); - ok = (quality >= 0.0f && quality <= 1.0f); - } - catch (boost::bad_lexical_cast&) - { - } - - if (ok) - { - return quality; - } - else - { - throw OrthancException( - ErrorCode_BadRequest, - "Quality parameter out of range in a HTTP request (must be between 0 and 1): " + value); - } - } - } - - return 1.0f; // Default quality - } - - - void HttpContentNegociation::SelectBestMatch(std::unique_ptr& best, - const Handler& handler, - const std::string& type, - const std::string& subtype, - float quality) - { - std::unique_ptr match(new Reference(handler, type, subtype, quality)); - - if (best.get() == NULL || - *best < *match) - { -#if __cplusplus < 201103L - best.reset(match.release()); -#else - best = std::move(match); -#endif - } - } - - - void HttpContentNegociation::Register(const std::string& mime, - IHandler& handler) - { - std::string type, subtype; - - if (SplitPair(type, subtype, mime, '/') && - type != "*" && - subtype != "*") - { - handlers_.push_back(Handler(type, subtype, handler)); - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool HttpContentNegociation::Apply(const HttpHeaders& headers) - { - HttpHeaders::const_iterator accept = headers.find("accept"); - if (accept != headers.end()) - { - return Apply(accept->second); - } - else - { - return Apply("*/*"); - } - } - - - bool HttpContentNegociation::Apply(const std::string& accept) - { - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 - // https://en.wikipedia.org/wiki/Content_negotiation - // http://www.newmediacampaigns.com/blog/browser-rest-http-accept-headers - - Tokens mediaRanges; - Toolbox::TokenizeString(mediaRanges, accept, ','); - - std::unique_ptr bestMatch; - - for (Tokens::const_iterator it = mediaRanges.begin(); - it != mediaRanges.end(); ++it) - { - Tokens parameters; - Toolbox::TokenizeString(parameters, *it, ';'); - - if (parameters.size() > 0) - { - float quality = GetQuality(parameters); - - std::string type, subtype; - if (SplitPair(type, subtype, parameters[0], '/')) - { - for (Handlers::const_iterator it2 = handlers_.begin(); - it2 != handlers_.end(); ++it2) - { - if (it2->IsMatch(type, subtype)) - { - SelectBestMatch(bestMatch, *it2, type, subtype, quality); - } - } - } - } - } - - if (bestMatch.get() == NULL) // No match was found - { - return false; - } - else - { - bestMatch->handler_.Call(); - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpContentNegociation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include "../Compatibility.h" - -#include -#include -#include -#include -#include -#include -#include - - -namespace Orthanc -{ - class HttpContentNegociation : public boost::noncopyable - { - public: - typedef std::map HttpHeaders; - - class IHandler : public boost::noncopyable - { - public: - virtual ~IHandler() - { - } - - virtual void Handle(const std::string& type, - const std::string& subtype) = 0; - }; - - private: - struct Handler - { - std::string type_; - std::string subtype_; - IHandler& handler_; - - Handler(const std::string& type, - const std::string& subtype, - IHandler& handler); - - bool IsMatch(const std::string& type, - const std::string& subtype) const; - - void Call() const - { - handler_.Handle(type_, subtype_); - } - }; - - - struct Reference; - - typedef std::vector Tokens; - typedef std::list Handlers; - - Handlers handlers_; - - - static bool SplitPair(std::string& first /* out */, - std::string& second /* out */, - const std::string& source, - char separator); - - static float GetQuality(const Tokens& parameters); - - static void SelectBestMatch(std::unique_ptr& best, - const Handler& handler, - const std::string& type, - const std::string& subtype, - float quality); - - public: - void Register(const std::string& mime, - IHandler& handler); - - bool Apply(const HttpHeaders& headers); - - bool Apply(const std::string& accept); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "HttpFileSender.h" - -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "../SystemToolbox.h" - -#include - -namespace Orthanc -{ - void HttpFileSender::SetContentFilename(const std::string& filename) - { - filename_ = filename; - - if (contentType_.empty()) - { - contentType_ = SystemToolbox::AutodetectMimeType(filename); - } - } - - - bool HttpFileSender::HasContentFilename(std::string& filename) - { - if (filename_.empty()) - { - return false; - } - else - { - filename = filename_; - return true; - } - } - - std::string HttpFileSender::GetContentType() - { - if (contentType_.empty()) - { - return MIME_BINARY; - } - else - { - return contentType_; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpFileSender.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "HttpOutput.h" - -namespace Orthanc -{ - class HttpFileSender : public IHttpStreamAnswer - { - private: - std::string contentType_; - std::string filename_; - - public: - void SetContentType(MimeType contentType) - { - contentType_ = EnumerationToString(contentType); - } - - void SetContentType(const std::string& contentType) - { - contentType_ = contentType; - } - - const std::string& GetContentType() const - { - return contentType_; - } - - void SetContentFilename(const std::string& filename); - - const std::string& GetContentFilename() const - { - return filename_; - } - - - /** - * Implementation of the IHttpStreamAnswer interface. - **/ - - virtual HttpCompression SetupHttpCompression(bool /*gzipAllowed*/, - bool /*deflateAllowed*/) - { - return HttpCompression_None; - } - - virtual bool HasContentFilename(std::string& filename); - - virtual std::string GetContentType(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,772 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "HttpOutput.h" - -#include "../ChunkedBuffer.h" -#include "../Compression/GzipCompressor.h" -#include "../Compression/ZlibCompressor.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#include -#include -#include -#include - - -#if ORTHANC_ENABLE_CIVETWEB == 1 -# if !defined(CIVETWEB_HAS_DISABLE_KEEP_ALIVE) -# error Macro CIVETWEB_HAS_DISABLE_KEEP_ALIVE must be defined -# endif -#endif - - -namespace Orthanc -{ - HttpOutput::StateMachine::StateMachine(IHttpOutputStream& stream, - bool isKeepAlive) : - stream_(stream), - state_(State_WritingHeader), - status_(HttpStatus_200_Ok), - hasContentLength_(false), - contentPosition_(0), - keepAlive_(isKeepAlive) - { - } - - HttpOutput::StateMachine::~StateMachine() - { - if (state_ != State_Done) - { - //asm volatile ("int3;"); - //LOG(ERROR) << "This HTTP answer does not contain any body"; - } - - if (hasContentLength_ && contentPosition_ != contentLength_) - { - LOG(ERROR) << "This HTTP answer has not sent the proper number of bytes in its body"; - } - } - - - void HttpOutput::StateMachine::SetHttpStatus(HttpStatus status) - { - if (state_ != State_WritingHeader) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - status_ = status; - } - - - void HttpOutput::StateMachine::SetContentLength(uint64_t length) - { - if (state_ != State_WritingHeader) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - hasContentLength_ = true; - contentLength_ = length; - } - - void HttpOutput::StateMachine::SetContentType(const char* contentType) - { - AddHeader("Content-Type", contentType); - } - - void HttpOutput::StateMachine::SetContentFilename(const char* filename) - { - // TODO Escape double quotes - AddHeader("Content-Disposition", "filename=\"" + std::string(filename) + "\""); - } - - void HttpOutput::StateMachine::SetCookie(const std::string& cookie, - const std::string& value) - { - if (state_ != State_WritingHeader) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - // TODO Escape "=" characters - AddHeader("Set-Cookie", cookie + "=" + value); - } - - - void HttpOutput::StateMachine::AddHeader(const std::string& header, - const std::string& value) - { - if (state_ != State_WritingHeader) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - headers_.push_back(header + ": " + value + "\r\n"); - } - - void HttpOutput::StateMachine::ClearHeaders() - { - if (state_ != State_WritingHeader) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - headers_.clear(); - } - - void HttpOutput::StateMachine::SendBody(const void* buffer, size_t length) - { - if (state_ == State_Done) - { - if (length == 0) - { - return; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Because of keep-alive connections, the entire body must " - "be sent at once or Content-Length must be given"); - } - } - - if (state_ == State_WritingMultipart) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (state_ == State_WritingHeader) - { - // Send the HTTP header before writing the body - - stream_.OnHttpStatusReceived(status_); - - std::string s = "HTTP/1.1 " + - boost::lexical_cast(status_) + - " " + std::string(EnumerationToString(status_)) + - "\r\n"; - - if (keepAlive_) - { - s += "Connection: keep-alive\r\n"; - } - else - { - s += "Connection: close\r\n"; - } - - for (std::list::const_iterator - it = headers_.begin(); it != headers_.end(); ++it) - { - s += *it; - } - - if (status_ != HttpStatus_200_Ok) - { - hasContentLength_ = false; - } - - uint64_t contentLength = (hasContentLength_ ? contentLength_ : length); - s += "Content-Length: " + boost::lexical_cast(contentLength) + "\r\n\r\n"; - - stream_.Send(true, s.c_str(), s.size()); - state_ = State_WritingBody; - } - - if (hasContentLength_ && - contentPosition_ + length > contentLength_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "The body size exceeds what was declared with SetContentSize()"); - } - - if (length > 0) - { - stream_.Send(false, buffer, length); - contentPosition_ += length; - } - - if (!hasContentLength_ || - contentPosition_ == contentLength_) - { - state_ = State_Done; - } - } - - - void HttpOutput::StateMachine::CloseBody() - { - switch (state_) - { - case State_WritingHeader: - SetContentLength(0); - SendBody(NULL, 0); - break; - - case State_WritingBody: - if (!hasContentLength_ || - contentPosition_ == contentLength_) - { - state_ = State_Done; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "The body size has not reached what was declared with SetContentSize()"); - } - - break; - - case State_WritingMultipart: - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Cannot invoke CloseBody() with multipart outputs"); - - case State_Done: - return; // Ignore - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - HttpCompression HttpOutput::GetPreferredCompression(size_t bodySize) const - { -#if 0 - // TODO Do not compress small files? - if (bodySize < 512) - { - return HttpCompression_None; - } -#endif - - // Prefer "gzip" over "deflate" if the choice is offered - - if (isGzipAllowed_) - { - return HttpCompression_Gzip; - } - else if (isDeflateAllowed_) - { - return HttpCompression_Deflate; - } - else - { - return HttpCompression_None; - } - } - - - void HttpOutput::SendMethodNotAllowed(const std::string& allowed) - { - stateMachine_.ClearHeaders(); - stateMachine_.SetHttpStatus(HttpStatus_405_MethodNotAllowed); - stateMachine_.AddHeader("Allow", allowed); - stateMachine_.SendBody(NULL, 0); - } - - - void HttpOutput::SendStatus(HttpStatus status, - const char* message, - size_t messageSize) - { - if (status == HttpStatus_301_MovedPermanently || - //status == HttpStatus_401_Unauthorized || - status == HttpStatus_405_MethodNotAllowed) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Please use the dedicated methods to this HTTP status code in HttpOutput"); - } - - stateMachine_.SetHttpStatus(status); - stateMachine_.SendBody(message, messageSize); - } - - - void HttpOutput::Redirect(const std::string& path) - { - stateMachine_.ClearHeaders(); - stateMachine_.SetHttpStatus(HttpStatus_301_MovedPermanently); - stateMachine_.AddHeader("Location", path); - stateMachine_.SendBody(NULL, 0); - } - - - void HttpOutput::SendUnauthorized(const std::string& realm) - { - stateMachine_.ClearHeaders(); - stateMachine_.SetHttpStatus(HttpStatus_401_Unauthorized); - stateMachine_.AddHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\""); - stateMachine_.SendBody(NULL, 0); - } - - - void HttpOutput::Answer(const void* buffer, - size_t length) - { - if (length == 0) - { - AnswerEmpty(); - return; - } - - HttpCompression compression = GetPreferredCompression(length); - - if (compression == HttpCompression_None) - { - stateMachine_.SetContentLength(length); - stateMachine_.SendBody(buffer, length); - return; - } - - std::string compressed, encoding; - - switch (compression) - { - case HttpCompression_Deflate: - { - encoding = "deflate"; - ZlibCompressor compressor; - // Do not prefix the buffer with its uncompressed size, to be compatible with "deflate" - compressor.SetPrefixWithUncompressedSize(false); - compressor.Compress(compressed, buffer, length); - break; - } - - case HttpCompression_Gzip: - { - encoding = "gzip"; - GzipCompressor compressor; - compressor.Compress(compressed, buffer, length); - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - LOG(TRACE) << "Compressing a HTTP answer using " << encoding; - - // The body is empty, do not use HTTP compression - if (compressed.size() == 0) - { - AnswerEmpty(); - } - else - { - stateMachine_.AddHeader("Content-Encoding", encoding); - stateMachine_.SetContentLength(compressed.size()); - stateMachine_.SendBody(compressed.c_str(), compressed.size()); - } - - stateMachine_.CloseBody(); - } - - - void HttpOutput::Answer(const std::string& str) - { - Answer(str.size() == 0 ? NULL : str.c_str(), str.size()); - } - - - void HttpOutput::AnswerEmpty() - { - stateMachine_.CloseBody(); - } - - - void HttpOutput::StateMachine::CheckHeadersCompatibilityWithMultipart() const - { - for (std::list::const_iterator - it = headers_.begin(); it != headers_.end(); ++it) - { - if (!Toolbox::StartsWith(*it, "Set-Cookie: ")) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "The only headers that can be set in multipart answers " - "are Set-Cookie (here: " + *it + " is set)"); - } - } - } - - - static void PrepareMultipartMainHeader(std::string& boundary, - std::string& contentTypeHeader, - const std::string& subType, - const std::string& contentType) - { - if (subType != "mixed" && - subType != "related") - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - /** - * Fix for issue 54 ("Decide what to do wrt. quoting of multipart - * answers"). The "type" parameter in the "Content-Type" HTTP - * header must be quoted if it contains a forward slash "/". This - * is necessary for DICOMweb compatibility with OsiriX, but breaks - * compatibility with old releases of the client in the Orthanc - * DICOMweb plugin <= 0.3 (releases >= 0.4 work fine). - * - * Full history is available at the following locations: - * - In changeset 2248:69b0f4e8a49b: - * # hg history -v -r 2248 - * - https://bitbucket.org/sjodogne/orthanc/issues/54/ - * - https://groups.google.com/d/msg/orthanc-users/65zhIM5xbKI/TU5Q1_LhAwAJ - **/ - std::string tmp; - if (contentType.find('/') == std::string::npos) - { - // No forward slash in the content type - tmp = contentType; - } - else - { - // Quote the content type because of the forward slash - tmp = "\"" + contentType + "\""; - } - - boundary = Toolbox::GenerateUuid() + "-" + Toolbox::GenerateUuid(); - - /** - * Fix for issue #165: "Encapsulation boundaries must not appear - * within the encapsulations, and must be no longer than 70 - * characters, not counting the two leading hyphens." - * https://tools.ietf.org/html/rfc1521 - * https://bitbucket.org/sjodogne/orthanc/issues/165/ - **/ - if (boundary.size() != 36 + 1 + 36) // one UUID contains 36 characters - { - throw OrthancException(ErrorCode_InternalError); - } - - boundary = boundary.substr(0, 70); - - contentTypeHeader = ("multipart/" + subType + "; type=" + tmp + "; boundary=" + boundary); - } - - - void HttpOutput::StateMachine::StartMultipart(const std::string& subType, - const std::string& contentType) - { - if (state_ != State_WritingHeader) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (status_ != HttpStatus_200_Ok) - { - SendBody(NULL, 0); - return; - } - - stream_.OnHttpStatusReceived(status_); - - std::string header = "HTTP/1.1 200 OK\r\n"; - - if (keepAlive_) - { -#if ORTHANC_ENABLE_MONGOOSE == 1 - throw OrthancException(ErrorCode_NotImplemented, - "Multipart answers are not implemented together " - "with keep-alive connections if using Mongoose"); - -#elif ORTHANC_ENABLE_CIVETWEB == 1 -# if CIVETWEB_HAS_DISABLE_KEEP_ALIVE == 1 - // Turn off Keep-Alive for multipart answers - // https://github.com/civetweb/civetweb/issues/727 - stream_.DisableKeepAlive(); - header += "Connection: close\r\n"; -# else - // The function "mg_disable_keep_alive()" is not available, - // let's continue with Keep-Alive. Performance of WADO-RS will - // decrease. - header += "Connection: keep-alive\r\n"; -# endif - -#else -# error Please support your embedded Web server here -#endif - } - else - { - header += "Connection: close\r\n"; - } - - // Possibly add the cookies - CheckHeadersCompatibilityWithMultipart(); - - for (std::list::const_iterator - it = headers_.begin(); it != headers_.end(); ++it) - { - header += *it; - } - - std::string contentTypeHeader; - PrepareMultipartMainHeader(multipartBoundary_, contentTypeHeader, subType, contentType); - multipartContentType_ = contentType; - header += ("Content-Type: " + contentTypeHeader + "\r\n\r\n"); - - stream_.Send(true, header.c_str(), header.size()); - state_ = State_WritingMultipart; - } - - - static void PrepareMultipartItemHeader(std::string& target, - size_t length, - const std::map& headers, - const std::string& boundary, - const std::string& contentType) - { - target = "--" + boundary + "\r\n"; - - bool hasContentType = false; - bool hasContentLength = false; - bool hasMimeVersion = false; - - for (std::map::const_iterator - it = headers.begin(); it != headers.end(); ++it) - { - target += it->first + ": " + it->second + "\r\n"; - - std::string tmp; - Toolbox::ToLowerCase(tmp, it->first); - - if (tmp == "content-type") - { - hasContentType = true; - } - - if (tmp == "content-length") - { - hasContentLength = true; - } - - if (tmp == "mime-version") - { - hasMimeVersion = true; - } - } - - if (!hasContentType) - { - target += "Content-Type: " + contentType + "\r\n"; - } - - if (!hasContentLength) - { - target += "Content-Length: " + boost::lexical_cast(length) + "\r\n"; - } - - if (!hasMimeVersion) - { - target += "MIME-Version: 1.0\r\n\r\n"; - } - } - - - void HttpOutput::StateMachine::SendMultipartItem(const void* item, - size_t length, - const std::map& headers) - { - if (state_ != State_WritingMultipart) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - std::string header; - PrepareMultipartItemHeader(header, length, headers, multipartBoundary_, multipartContentType_); - stream_.Send(false, header.c_str(), header.size()); - - if (length > 0) - { - stream_.Send(false, item, length); - } - - stream_.Send(false, "\r\n", 2); - } - - - void HttpOutput::StateMachine::CloseMultipart() - { - if (state_ != State_WritingMultipart) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - // The two lines below might throw an exception, if the client has - // closed the connection. Such an error is ignored. - try - { - std::string header = "--" + multipartBoundary_ + "--\r\n"; - stream_.Send(false, header.c_str(), header.size()); - } - catch (OrthancException&) - { - } - - state_ = State_Done; - } - - - static void AnswerStreamAsBuffer(HttpOutput& output, - IHttpStreamAnswer& stream) - { - ChunkedBuffer buffer; - - while (stream.ReadNextChunk()) - { - if (stream.GetChunkSize() > 0) - { - buffer.AddChunk(stream.GetChunkContent(), stream.GetChunkSize()); - } - } - - std::string s; - buffer.Flatten(s); - - output.SetContentType(stream.GetContentType()); - - std::string filename; - if (stream.HasContentFilename(filename)) - { - output.SetContentFilename(filename.c_str()); - } - - output.Answer(s); - } - - - void HttpOutput::Answer(IHttpStreamAnswer& stream) - { - HttpCompression compression = stream.SetupHttpCompression(isGzipAllowed_, isDeflateAllowed_); - - switch (compression) - { - case HttpCompression_None: - { - if (isGzipAllowed_ || isDeflateAllowed_) - { - // New in Orthanc 1.5.7: Compress streams without built-in - // compression, if requested by the "Accept-Encoding" HTTP - // header - AnswerStreamAsBuffer(*this, stream); - return; - } - - break; - } - - case HttpCompression_Gzip: - stateMachine_.AddHeader("Content-Encoding", "gzip"); - break; - - case HttpCompression_Deflate: - stateMachine_.AddHeader("Content-Encoding", "deflate"); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - stateMachine_.SetContentLength(stream.GetContentLength()); - - std::string contentType = stream.GetContentType(); - if (contentType.empty()) - { - contentType = MIME_BINARY; - } - - stateMachine_.SetContentType(contentType.c_str()); - - std::string filename; - if (stream.HasContentFilename(filename)) - { - SetContentFilename(filename.c_str()); - } - - while (stream.ReadNextChunk()) - { - stateMachine_.SendBody(stream.GetChunkContent(), - stream.GetChunkSize()); - } - - stateMachine_.CloseBody(); - } - - - void HttpOutput::AnswerMultipartWithoutChunkedTransfer( - const std::string& subType, - const std::string& contentType, - const std::vector& parts, - const std::vector& sizes, - const std::vector*>& headers) - { - if (parts.size() != sizes.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - stateMachine_.CheckHeadersCompatibilityWithMultipart(); - - std::string boundary, contentTypeHeader; - PrepareMultipartMainHeader(boundary, contentTypeHeader, subType, contentType); - SetContentType(contentTypeHeader); - - std::map empty; - - ChunkedBuffer chunked; - for (size_t i = 0; i < parts.size(); i++) - { - std::string partHeader; - PrepareMultipartItemHeader(partHeader, sizes[i], headers[i] == NULL ? empty : *headers[i], - boundary, contentType); - - chunked.AddChunk(partHeader); - chunked.AddChunk(parts[i], sizes[i]); - chunked.AddChunk("\r\n"); - } - - chunked.AddChunk("--" + boundary + "--\r\n"); - - std::string body; - chunked.Flatten(body); - Answer(body); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpOutput.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,250 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" -#include "IHttpOutputStream.h" -#include "IHttpStreamAnswer.h" - -#include -#include -#include -#include -#include - -namespace Orthanc -{ - class HttpOutput : public boost::noncopyable - { - private: - typedef std::list< std::pair > Header; - - class StateMachine : public boost::noncopyable - { - public: - enum State - { - State_WritingHeader, - State_WritingBody, - State_WritingMultipart, - State_Done - }; - - private: - IHttpOutputStream& stream_; - State state_; - - HttpStatus status_; - bool hasContentLength_; - uint64_t contentLength_; - uint64_t contentPosition_; - bool keepAlive_; - std::list headers_; - - std::string multipartBoundary_; - std::string multipartContentType_; - - public: - StateMachine(IHttpOutputStream& stream, - bool isKeepAlive); - - ~StateMachine(); - - void SetHttpStatus(HttpStatus status); - - void SetContentLength(uint64_t length); - - void SetContentType(const char* contentType); - - void SetContentFilename(const char* filename); - - void SetCookie(const std::string& cookie, - const std::string& value); - - void AddHeader(const std::string& header, - const std::string& value); - - void ClearHeaders(); - - void SendBody(const void* buffer, size_t length); - - void StartMultipart(const std::string& subType, - const std::string& contentType); - - void SendMultipartItem(const void* item, - size_t length, - const std::map& headers); - - void CloseMultipart(); - - void CloseBody(); - - State GetState() const - { - return state_; - } - - void CheckHeadersCompatibilityWithMultipart() const; - }; - - StateMachine stateMachine_; - bool isDeflateAllowed_; - bool isGzipAllowed_; - - HttpCompression GetPreferredCompression(size_t bodySize) const; - - public: - HttpOutput(IHttpOutputStream& stream, - bool isKeepAlive) : - stateMachine_(stream, isKeepAlive), - isDeflateAllowed_(false), - isGzipAllowed_(false) - { - } - - void SetDeflateAllowed(bool allowed) - { - isDeflateAllowed_ = allowed; - } - - bool IsDeflateAllowed() const - { - return isDeflateAllowed_; - } - - void SetGzipAllowed(bool allowed) - { - isGzipAllowed_ = allowed; - } - - bool IsGzipAllowed() const - { - return isGzipAllowed_; - } - - void SendStatus(HttpStatus status, - const char* message, - size_t messageSize); - - void SendStatus(HttpStatus status) - { - SendStatus(status, NULL, 0); - } - - void SendStatus(HttpStatus status, - const std::string& message) - { - SendStatus(status, message.c_str(), message.size()); - } - - void SetContentType(MimeType contentType) - { - stateMachine_.SetContentType(EnumerationToString(contentType)); - } - - void SetContentType(const std::string& contentType) - { - stateMachine_.SetContentType(contentType.c_str()); - } - - void SetContentFilename(const char* filename) - { - stateMachine_.SetContentFilename(filename); - } - - void SetCookie(const std::string& cookie, - const std::string& value) - { - stateMachine_.SetCookie(cookie, value); - } - - void AddHeader(const std::string& key, - const std::string& value) - { - stateMachine_.AddHeader(key, value); - } - - void Answer(const void* buffer, - size_t length); - - void Answer(const std::string& str); - - void AnswerEmpty(); - - void SendMethodNotAllowed(const std::string& allowed); - - void Redirect(const std::string& path); - - void SendUnauthorized(const std::string& realm); - - void StartMultipart(const std::string& subType, - const std::string& contentType) - { - stateMachine_.StartMultipart(subType, contentType); - } - - void SendMultipartItem(const void* item, - size_t size, - const std::map& headers) - { - stateMachine_.SendMultipartItem(item, size, headers); - } - - void CloseMultipart() - { - stateMachine_.CloseMultipart(); - } - - bool IsWritingMultipart() const - { - return stateMachine_.GetState() == StateMachine::State_WritingMultipart; - } - - void Answer(IHttpStreamAnswer& stream); - - /** - * This method is a replacement to the combination - * "StartMultipart()" + "SendMultipartItem()". It generates the - * same answer, but it gives a chance to compress the body if - * "Accept-Encoding: gzip" is provided by the client, which is not - * possible in chunked transfers. - **/ - void AnswerMultipartWithoutChunkedTransfer( - const std::string& subType, - const std::string& contentType, - const std::vector& parts, - const std::vector& sizes, - const std::vector*>& headers); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1385 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -// http://en.highscore.de/cpp/boost/stringhandling.html - -#include "../PrecompiledHeaders.h" -#include "HttpServer.h" - -#include "../ChunkedBuffer.h" -#include "../FileBuffer.h" -#include "../Logging.h" -#include "../OrthancException.h" -#include "../TemporaryFile.h" -#include "HttpToolbox.h" - -#if ORTHANC_ENABLE_MONGOOSE == 1 -# include - -#elif ORTHANC_ENABLE_CIVETWEB == 1 -# include -# define MONGOOSE_USE_CALLBACKS 1 -# if !defined(CIVETWEB_HAS_DISABLE_KEEP_ALIVE) -# error Macro CIVETWEB_HAS_DISABLE_KEEP_ALIVE must be defined -# endif - -#else -# error "Either Mongoose or Civetweb must be enabled to compile this file" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(ORTHANC_ENABLE_SSL) -# error The macro ORTHANC_ENABLE_SSL must be defined -#endif - -#if ORTHANC_ENABLE_SSL == 1 -# include -# include -#endif - -#define ORTHANC_REALM "Orthanc Secure Area" - - -namespace Orthanc -{ - static const char MULTIPART_FORM[] = "multipart/form-data; boundary="; - static unsigned int MULTIPART_FORM_LENGTH = sizeof(MULTIPART_FORM) / sizeof(char) - 1; - - - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - class MongooseOutputStream : public IHttpOutputStream - { - private: - struct mg_connection* connection_; - - public: - MongooseOutputStream(struct mg_connection* connection) : connection_(connection) - { - } - - virtual void Send(bool isHeader, const void* buffer, size_t length) - { - if (length > 0) - { - int status = mg_write(connection_, buffer, length); - if (status != static_cast(length)) - { - // status == 0 when the connection has been closed, -1 on error - throw OrthancException(ErrorCode_NetworkProtocol); - } - } - } - - virtual void OnHttpStatusReceived(HttpStatus status) - { - // Ignore this - } - - virtual void DisableKeepAlive() - { -#if ORTHANC_ENABLE_MONGOOSE == 1 - throw OrthancException(ErrorCode_NotImplemented, - "Only available if using CivetWeb"); - -#elif ORTHANC_ENABLE_CIVETWEB == 1 -# if CIVETWEB_HAS_DISABLE_KEEP_ALIVE == 1 - mg_disable_keep_alive(connection_); -# else -# warning The function "mg_disable_keep_alive()" is not available, DICOMweb might run slowly - throw OrthancException(ErrorCode_NotImplemented, - "Only available if using a patched version of CivetWeb"); -# endif - -#else -# error Please support your embedded Web server here -#endif - } - }; - - - enum PostDataStatus - { - PostDataStatus_Success, - PostDataStatus_NoLength, - PostDataStatus_Pending, - PostDataStatus_Failure - }; - } - - -// TODO Move this to external file - - - class ChunkedFile : public ChunkedBuffer - { - private: - std::string filename_; - - public: - ChunkedFile(const std::string& filename) : - filename_(filename) - { - } - - const std::string& GetFilename() const - { - return filename_; - } - }; - - - - class ChunkStore : public boost::noncopyable - { - private: - typedef std::list Content; - Content content_; - unsigned int numPlaces_; - - boost::mutex mutex_; - std::set discardedFiles_; - - void Clear() - { - for (Content::iterator it = content_.begin(); - it != content_.end(); ++it) - { - delete *it; - } - } - - Content::iterator Find(const std::string& filename) - { - for (Content::iterator it = content_.begin(); - it != content_.end(); ++it) - { - if ((*it)->GetFilename() == filename) - { - return it; - } - } - - return content_.end(); - } - - void Remove(const std::string& filename) - { - Content::iterator it = Find(filename); - if (it != content_.end()) - { - delete *it; - content_.erase(it); - } - } - - public: - ChunkStore() - { - numPlaces_ = 10; - } - - ~ChunkStore() - { - Clear(); - } - - PostDataStatus Store(std::string& completed, - const char* chunkData, - size_t chunkSize, - const std::string& filename, - size_t filesize) - { - boost::mutex::scoped_lock lock(mutex_); - - std::set::iterator wasDiscarded = discardedFiles_.find(filename); - if (wasDiscarded != discardedFiles_.end()) - { - discardedFiles_.erase(wasDiscarded); - return PostDataStatus_Failure; - } - - ChunkedFile* f; - Content::iterator it = Find(filename); - if (it == content_.end()) - { - f = new ChunkedFile(filename); - - // Make some room - if (content_.size() >= numPlaces_) - { - discardedFiles_.insert(content_.front()->GetFilename()); - delete content_.front(); - content_.pop_front(); - } - - content_.push_back(f); - } - else - { - f = *it; - } - - f->AddChunk(chunkData, chunkSize); - - if (f->GetNumBytes() > filesize) - { - Remove(filename); - } - else if (f->GetNumBytes() == filesize) - { - f->Flatten(completed); - Remove(filename); - return PostDataStatus_Success; - } - - return PostDataStatus_Pending; - } - - /*void Print() - { - boost::mutex::scoped_lock lock(mutex_); - - printf("ChunkStore status:\n"); - for (Content::const_iterator i = content_.begin(); - i != content_.end(); i++) - { - printf(" [%s]: %d\n", (*i)->GetFilename().c_str(), (*i)->GetNumBytes()); - } - printf("-----\n"); - }*/ - }; - - - struct HttpServer::PImpl - { - struct mg_context *context_; - ChunkStore chunkStore_; - }; - - - ChunkStore& HttpServer::GetChunkStore() - { - return pimpl_->chunkStore_; - } - - - static PostDataStatus ReadBodyWithContentLength(std::string& body, - struct mg_connection *connection, - const std::string& contentLength) - { - int length; - try - { - length = boost::lexical_cast(contentLength); - } - catch (boost::bad_lexical_cast&) - { - return PostDataStatus_NoLength; - } - - if (length < 0) - { - length = 0; - } - - body.resize(length); - - size_t pos = 0; - while (length > 0) - { - int r = mg_read(connection, &body[pos], length); - if (r <= 0) - { - return PostDataStatus_Failure; - } - - assert(r <= length); - length -= r; - pos += r; - } - - return PostDataStatus_Success; - } - - - static PostDataStatus ReadBodyToString(std::string& body, - struct mg_connection *connection, - const IHttpHandler::Arguments& headers) - { - IHttpHandler::Arguments::const_iterator contentLength = headers.find("content-length"); - - if (contentLength != headers.end()) - { - // "Content-Length" is available - return ReadBodyWithContentLength(body, connection, contentLength->second); - } - else - { - // No Content-Length. Store the individual chunks in a temporary - // file, then read it back into the memory buffer "body" - FileBuffer buffer; - - std::string tmp(1024 * 1024, 0); - - for (;;) - { - int r = mg_read(connection, &tmp[0], tmp.size()); - if (r < 0) - { - return PostDataStatus_Failure; - } - else if (r == 0) - { - break; - } - else - { - buffer.Append(tmp.c_str(), r); - } - } - - buffer.Read(body); - - return PostDataStatus_Success; - } - } - - - static PostDataStatus ReadBodyToStream(IHttpHandler::IChunkedRequestReader& stream, - struct mg_connection *connection, - const IHttpHandler::Arguments& headers) - { - IHttpHandler::Arguments::const_iterator contentLength = headers.find("content-length"); - - if (contentLength != headers.end()) - { - // "Content-Length" is available - std::string body; - PostDataStatus status = ReadBodyWithContentLength(body, connection, contentLength->second); - - if (status == PostDataStatus_Success && - !body.empty()) - { - stream.AddBodyChunk(body.c_str(), body.size()); - } - - return status; - } - else - { - // No Content-Length: This is a chunked transfer. Stream the HTTP connection. - std::string tmp(1024 * 1024, 0); - - for (;;) - { - int r = mg_read(connection, &tmp[0], tmp.size()); - if (r < 0) - { - return PostDataStatus_Failure; - } - else if (r == 0) - { - break; - } - else - { - stream.AddBodyChunk(tmp.c_str(), r); - } - } - - return PostDataStatus_Success; - } - } - - - static PostDataStatus ParseMultipartForm(std::string &completedFile, - struct mg_connection *connection, - const IHttpHandler::Arguments& headers, - const std::string& contentType, - ChunkStore& chunkStore) - { - std::string boundary = "--" + contentType.substr(MULTIPART_FORM_LENGTH); - - std::string body; - PostDataStatus status = ReadBodyToString(body, connection, headers); - - if (status != PostDataStatus_Success) - { - return status; - } - - /*for (IHttpHandler::Arguments::const_iterator i = headers.begin(); i != headers.end(); i++) - { - std::cout << "Header [" << i->first << "] = " << i->second << "\n"; - } - printf("CHUNK\n");*/ - - typedef IHttpHandler::Arguments::const_iterator ArgumentIterator; - - ArgumentIterator requestedWith = headers.find("x-requested-with"); - ArgumentIterator fileName = headers.find("x-file-name"); - ArgumentIterator fileSizeStr = headers.find("x-file-size"); - - if (requestedWith != headers.end() && - requestedWith->second != "XMLHttpRequest") - { - return PostDataStatus_Failure; - } - - size_t fileSize = 0; - if (fileSizeStr != headers.end()) - { - try - { - fileSize = boost::lexical_cast(fileSizeStr->second); - } - catch (boost::bad_lexical_cast&) - { - return PostDataStatus_Failure; - } - } - - typedef boost::find_iterator FindIterator; - typedef boost::iterator_range Range; - - //chunkStore.Print(); - - // TODO - Refactor using class "MultipartStreamReader" - try - { - FindIterator last; - for (FindIterator it = - make_find_iterator(body, boost::first_finder(boundary)); - it!=FindIterator(); - ++it) - { - if (last != FindIterator()) - { - Range part(&last->back(), &it->front()); - Range content = boost::find_first(part, "\r\n\r\n"); - if (/*content != Range()*/!content.empty()) - { - Range c(&content.back() + 1, &it->front() - 2); - size_t chunkSize = c.size(); - - if (chunkSize > 0) - { - const char* chunkData = &c.front(); - - if (fileName == headers.end()) - { - // This file is stored in a single chunk - completedFile.resize(chunkSize); - if (chunkSize > 0) - { - memcpy(&completedFile[0], chunkData, chunkSize); - } - return PostDataStatus_Success; - } - else - { - return chunkStore.Store(completedFile, chunkData, chunkSize, fileName->second, fileSize); - } - } - } - } - - last = it; - } - } - catch (std::length_error&) - { - return PostDataStatus_Failure; - } - - return PostDataStatus_Pending; - } - - - static bool IsAccessGranted(const HttpServer& that, - const IHttpHandler::Arguments& headers) - { - bool granted = false; - - IHttpHandler::Arguments::const_iterator auth = headers.find("authorization"); - if (auth != headers.end()) - { - std::string s = auth->second; - if (s.size() > 6 && - s.substr(0, 6) == "Basic ") - { - std::string b64 = s.substr(6); - granted = that.IsValidBasicHttpAuthentication(b64); - } - } - - return granted; - } - - - static std::string GetAuthenticatedUsername(const IHttpHandler::Arguments& headers) - { - IHttpHandler::Arguments::const_iterator auth = headers.find("authorization"); - - if (auth == headers.end()) - { - return ""; - } - - std::string s = auth->second; - if (s.size() <= 6 || - s.substr(0, 6) != "Basic ") - { - return ""; - } - - std::string b64 = s.substr(6); - std::string decoded; - Toolbox::DecodeBase64(decoded, b64); - size_t semicolons = decoded.find(':'); - - if (semicolons == std::string::npos) - { - // Bad-formatted request - return ""; - } - else - { - return decoded.substr(0, semicolons); - } - } - - - static bool ExtractMethod(HttpMethod& method, - const struct mg_request_info *request, - const IHttpHandler::Arguments& headers, - const IHttpHandler::GetArguments& argumentsGET) - { - std::string overriden; - - // Check whether some PUT/DELETE faking is done - - // 1. Faking with Google's approach - IHttpHandler::Arguments::const_iterator methodOverride = - headers.find("x-http-method-override"); - - if (methodOverride != headers.end()) - { - overriden = methodOverride->second; - } - else if (!strcmp(request->request_method, "GET")) - { - // 2. Faking with Ruby on Rail's approach - // GET /my/resource?_method=delete <=> DELETE /my/resource - for (size_t i = 0; i < argumentsGET.size(); i++) - { - if (argumentsGET[i].first == "_method") - { - overriden = argumentsGET[i].second; - break; - } - } - } - - if (overriden.size() > 0) - { - // A faking has been done within this request - Toolbox::ToUpperCase(overriden); - - LOG(INFO) << "HTTP method faking has been detected for " << overriden; - - if (overriden == "PUT") - { - method = HttpMethod_Put; - return true; - } - else if (overriden == "DELETE") - { - method = HttpMethod_Delete; - return true; - } - else - { - return false; - } - } - - // No PUT/DELETE faking was present - if (!strcmp(request->request_method, "GET")) - { - method = HttpMethod_Get; - } - else if (!strcmp(request->request_method, "POST")) - { - method = HttpMethod_Post; - } - else if (!strcmp(request->request_method, "DELETE")) - { - method = HttpMethod_Delete; - } - else if (!strcmp(request->request_method, "PUT")) - { - method = HttpMethod_Put; - } - else - { - return false; - } - - return true; - } - - - static void ConfigureHttpCompression(HttpOutput& output, - const IHttpHandler::Arguments& headers) - { - // Look if the client wishes HTTP compression - // https://en.wikipedia.org/wiki/HTTP_compression - IHttpHandler::Arguments::const_iterator it = headers.find("accept-encoding"); - if (it != headers.end()) - { - std::vector encodings; - Toolbox::TokenizeString(encodings, it->second, ','); - - for (size_t i = 0; i < encodings.size(); i++) - { - std::string s = Toolbox::StripSpaces(encodings[i]); - - if (s == "deflate") - { - output.SetDeflateAllowed(true); - } - else if (s == "gzip") - { - output.SetGzipAllowed(true); - } - } - } - } - - - static void InternalCallback(HttpOutput& output /* out */, - HttpMethod& method /* out */, - HttpServer& server, - struct mg_connection *connection, - const struct mg_request_info *request) - { - bool localhost; - -#if ORTHANC_ENABLE_MONGOOSE == 1 - static const long LOCALHOST = (127ll << 24) + 1ll; - localhost = (request->remote_ip == LOCALHOST); -#elif ORTHANC_ENABLE_CIVETWEB == 1 - // The "remote_ip" field of "struct mg_request_info" is tagged as - // deprecated in Civetweb, using "remote_addr" instead. - localhost = (std::string(request->remote_addr) == "127.0.0.1"); -#else -# error -#endif - - // Check remote calls - if (!server.IsRemoteAccessAllowed() && - !localhost) - { - output.SendUnauthorized(server.GetRealm()); - return; - } - - - // Extract the HTTP headers - IHttpHandler::Arguments headers; - for (int i = 0; i < request->num_headers; i++) - { - std::string name = request->http_headers[i].name; - std::string value = request->http_headers[i].value; - - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - headers.insert(std::make_pair(name, value)); - VLOG(1) << "HTTP header: [" << name << "]: [" << value << "]"; - } - - if (server.IsHttpCompressionEnabled()) - { - ConfigureHttpCompression(output, headers); - } - - - // Extract the GET arguments - IHttpHandler::GetArguments argumentsGET; - if (!strcmp(request->request_method, "GET")) - { - HttpToolbox::ParseGetArguments(argumentsGET, request->query_string); - } - - - // Compute the HTTP method, taking method faking into consideration - method = HttpMethod_Get; - if (!ExtractMethod(method, request, headers, argumentsGET)) - { - output.SendStatus(HttpStatus_400_BadRequest); - return; - } - - - // Authenticate this connection - if (server.IsAuthenticationEnabled() && - !IsAccessGranted(server, headers)) - { - output.SendUnauthorized(server.GetRealm()); - return; - } - - -#if ORTHANC_ENABLE_MONGOOSE == 1 - // Apply the filter, if it is installed - char remoteIp[24]; - sprintf(remoteIp, "%d.%d.%d.%d", - reinterpret_cast(&request->remote_ip) [3], - reinterpret_cast(&request->remote_ip) [2], - reinterpret_cast(&request->remote_ip) [1], - reinterpret_cast(&request->remote_ip) [0]); - - const char* requestUri = request->uri; - -#elif ORTHANC_ENABLE_CIVETWEB == 1 - const char* remoteIp = request->remote_addr; - const char* requestUri = request->local_uri; -#else -# error -#endif - - if (requestUri == NULL) - { - requestUri = ""; - } - - std::string username = GetAuthenticatedUsername(headers); - - IIncomingHttpRequestFilter *filter = server.GetIncomingHttpRequestFilter(); - if (filter != NULL) - { - if (!filter->IsAllowed(method, requestUri, remoteIp, - username.c_str(), headers, argumentsGET)) - { - //output.SendUnauthorized(server.GetRealm()); - output.SendStatus(HttpStatus_403_Forbidden); - return; - } - } - - - // Decompose the URI into its components - UriComponents uri; - try - { - Toolbox::SplitUriComponents(uri, requestUri); - } - catch (OrthancException&) - { - output.SendStatus(HttpStatus_400_BadRequest); - return; - } - - LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); - - - bool found = false; - - // Extract the body of the request for PUT and POST, or process - // the body as a stream - - // TODO Avoid unneccessary memcopy of the body - - std::string body; - if (method == HttpMethod_Post || - method == HttpMethod_Put) - { - PostDataStatus status; - - bool isMultipartForm = false; - - IHttpHandler::Arguments::const_iterator ct = headers.find("content-type"); - if (ct != headers.end() && - ct->second.size() >= MULTIPART_FORM_LENGTH && - !memcmp(ct->second.c_str(), MULTIPART_FORM, MULTIPART_FORM_LENGTH)) - { - /** - * The user uses the "upload" form of Orthanc Explorer, for - * file uploads through a HTML form. - **/ - status = ParseMultipartForm(body, connection, headers, ct->second, server.GetChunkStore()); - isMultipartForm = true; - } - - if (!isMultipartForm) - { - std::unique_ptr stream; - - if (server.HasHandler()) - { - found = server.GetHandler().CreateChunkedRequestReader - (stream, RequestOrigin_RestApi, remoteIp, username.c_str(), method, uri, headers); - } - - if (found) - { - if (stream.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - status = ReadBodyToStream(*stream, connection, headers); - - if (status == PostDataStatus_Success) - { - stream->Execute(output); - } - } - else - { - status = ReadBodyToString(body, connection, headers); - } - } - - switch (status) - { - case PostDataStatus_NoLength: - output.SendStatus(HttpStatus_411_LengthRequired); - return; - - case PostDataStatus_Failure: - output.SendStatus(HttpStatus_400_BadRequest); - return; - - case PostDataStatus_Pending: - output.AnswerEmpty(); - return; - - case PostDataStatus_Success: - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - if (!found && - server.HasHandler()) - { - found = server.GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(), - method, uri, headers, argumentsGET, body.c_str(), body.size()); - } - - if (!found) - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - - static void ProtectedCallback(struct mg_connection *connection, - const struct mg_request_info *request) - { - try - { -#if ORTHANC_ENABLE_MONGOOSE == 1 - void *that = request->user_data; - const char* requestUri = request->uri; -#elif ORTHANC_ENABLE_CIVETWEB == 1 - // https://github.com/civetweb/civetweb/issues/409 - void *that = mg_get_user_data(mg_get_context(connection)); - const char* requestUri = request->local_uri; -#else -# error -#endif - - if (requestUri == NULL) - { - requestUri = ""; - } - - HttpServer* server = reinterpret_cast(that); - - if (server == NULL) - { - MongooseOutputStream stream(connection); - HttpOutput output(stream, false /* assume no keep-alive */); - output.SendStatus(HttpStatus_500_InternalServerError); - return; - } - - MongooseOutputStream stream(connection); - HttpOutput output(stream, server->IsKeepAliveEnabled()); - HttpMethod method = HttpMethod_Get; - - try - { - try - { - InternalCallback(output, method, *server, connection, request); - } - catch (OrthancException&) - { - throw; // Pass the exception to the main handler below - } - // Now convert native exceptions as OrthancException - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_BadParameterType, - "Syntax error in some user-supplied data"); - } - catch (boost::filesystem::filesystem_error& e) - { - throw OrthancException(ErrorCode_InternalError, - "Error while accessing the filesystem: " + e.path1().string()); - } - catch (std::runtime_error&) - { - throw OrthancException(ErrorCode_BadRequest, - "Presumably an error while parsing the JSON body"); - } - catch (std::bad_alloc&) - { - throw OrthancException(ErrorCode_NotEnoughMemory, - "The server hosting Orthanc is running out of memory"); - } - catch (...) - { - throw OrthancException(ErrorCode_InternalError, - "An unhandled exception was generated inside the HTTP server"); - } - } - catch (OrthancException& e) - { - assert(server != NULL); - - // Using this candidate handler results in an exception - try - { - if (server->GetExceptionFormatter() == NULL) - { - LOG(ERROR) << "Exception in the HTTP handler: " << e.What(); - output.SendStatus(e.GetHttpStatus()); - } - else - { - server->GetExceptionFormatter()->Format(output, e, method, requestUri); - } - } - catch (OrthancException&) - { - // An exception here reflects the fact that the status code - // was already set by the HTTP handler. - } - } - } - catch (...) - { - // We should never arrive at this point, where it is even impossible to send an answer - LOG(ERROR) << "Catastrophic error inside the HTTP server, giving up"; - } - } - - -#if MONGOOSE_USE_CALLBACKS == 0 - static void* Callback(enum mg_event event, - struct mg_connection *connection, - const struct mg_request_info *request) - { - if (event == MG_NEW_REQUEST) - { - ProtectedCallback(connection, request); - - // Mark as processed - return (void*) ""; - } - else - { - return NULL; - } - } - -#elif MONGOOSE_USE_CALLBACKS == 1 - static int Callback(struct mg_connection *connection) - { - const struct mg_request_info *request = mg_get_request_info(connection); - - ProtectedCallback(connection, request); - - return 1; // Do not let Mongoose handle the request by itself - } - -#else -# error Please set MONGOOSE_USE_CALLBACKS -#endif - - - - - - bool HttpServer::IsRunning() const - { - return (pimpl_->context_ != NULL); - } - - - HttpServer::HttpServer() : pimpl_(new PImpl) - { - pimpl_->context_ = NULL; - handler_ = NULL; - remoteAllowed_ = false; - authentication_ = false; - ssl_ = false; - port_ = 8000; - filter_ = NULL; - keepAlive_ = false; - httpCompression_ = true; - exceptionFormatter_ = NULL; - realm_ = ORTHANC_REALM; - threadsCount_ = 50; // Default value in mongoose - tcpNoDelay_ = true; - requestTimeout_ = 30; // Default value in mongoose/civetweb (30 seconds) - -#if ORTHANC_ENABLE_MONGOOSE == 1 - LOG(INFO) << "This Orthanc server uses Mongoose as its embedded HTTP server"; -#endif - -#if ORTHANC_ENABLE_CIVETWEB == 1 - LOG(INFO) << "This Orthanc server uses CivetWeb as its embedded HTTP server"; -#endif - -#if ORTHANC_ENABLE_SSL == 1 - // Check for the Heartbleed exploit - // https://en.wikipedia.org/wiki/OpenSSL#Heartbleed_bug - if (OPENSSL_VERSION_NUMBER < 0x1000107fL /* openssl-1.0.1g */ && - OPENSSL_VERSION_NUMBER >= 0x1000100fL /* openssl-1.0.1 */) - { - LOG(WARNING) << "This version of OpenSSL is vulnerable to the Heartbleed exploit"; - } -#endif - } - - - HttpServer::~HttpServer() - { - Stop(); - } - - - void HttpServer::SetPortNumber(uint16_t port) - { - Stop(); - port_ = port; - } - - void HttpServer::Start() - { -#if ORTHANC_ENABLE_MONGOOSE == 1 - LOG(INFO) << "Starting embedded Web server using Mongoose"; -#elif ORTHANC_ENABLE_CIVETWEB == 1 - LOG(INFO) << "Starting embedded Web server using Civetweb"; -#else -# error -#endif - - if (!IsRunning()) - { - std::string port = boost::lexical_cast(port_); - std::string numThreads = boost::lexical_cast(threadsCount_); - std::string requestTimeoutMilliseconds = boost::lexical_cast(requestTimeout_ * 1000); - - if (ssl_) - { - port += "s"; - } - - const char *options[] = { - // Set the TCP port for the HTTP server - "listening_ports", port.c_str(), - - // Optimization reported by Chris Hafey - // https://groups.google.com/d/msg/orthanc-users/CKueKX0pJ9E/_UCbl8T-VjIJ - "enable_keep_alive", (keepAlive_ ? "yes" : "no"), - -#if ORTHANC_ENABLE_CIVETWEB == 1 - // https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md#enable_keep_alive-no - "keep_alive_timeout_ms", (keepAlive_ ? "500" : "0"), -#endif - -#if ORTHANC_ENABLE_CIVETWEB == 1 - // Disable TCP Nagle's algorithm to maximize speed (this - // option is not available in Mongoose). - // https://groups.google.com/d/topic/civetweb/35HBR9seFjU/discussion - // https://eklitzke.org/the-caveats-of-tcp-nodelay - "tcp_nodelay", (tcpNoDelay_ ? "1" : "0"), -#endif - - // Set the number of threads - "num_threads", numThreads.c_str(), - - // Set the timeout for the HTTP server - "request_timeout_ms", requestTimeoutMilliseconds.c_str(), - - // Set the SSL certificate, if any. This must be the last option. - ssl_ ? "ssl_certificate" : NULL, - certificate_.c_str(), - NULL - }; - -#if MONGOOSE_USE_CALLBACKS == 0 - pimpl_->context_ = mg_start(&Callback, this, options); - -#elif MONGOOSE_USE_CALLBACKS == 1 - struct mg_callbacks callbacks; - memset(&callbacks, 0, sizeof(callbacks)); - callbacks.begin_request = Callback; - pimpl_->context_ = mg_start(&callbacks, this, options); - -#else -# error Please set MONGOOSE_USE_CALLBACKS -#endif - - if (!pimpl_->context_) - { - bool isSslError = false; - -#if ORTHANC_ENABLE_SSL == 1 - for (;;) - { - unsigned long code = ERR_get_error(); - if (code == 0) - { - break; - } - else - { - isSslError = true; - char message[1024]; - ERR_error_string_n(code, message, sizeof(message) - 1); - LOG(ERROR) << "OpenSSL error: " << message; - } - } -#endif - - if (isSslError) - { - throw OrthancException(ErrorCode_SslInitialization); - } - else - { - throw OrthancException(ErrorCode_HttpPortInUse, - " (port = " + boost::lexical_cast(port_) + ")"); - } - } - - LOG(WARNING) << "HTTP server listening on port: " << GetPortNumber() - << " (HTTPS encryption is " - << (IsSslEnabled() ? "enabled" : "disabled") - << ", remote access is " - << (IsRemoteAccessAllowed() ? "" : "not ") - << "allowed)"; - } - } - - void HttpServer::Stop() - { - if (IsRunning()) - { - mg_stop(pimpl_->context_); - pimpl_->context_ = NULL; - } - } - - - void HttpServer::ClearUsers() - { - Stop(); - registeredUsers_.clear(); - } - - - void HttpServer::RegisterUser(const char* username, - const char* password) - { - Stop(); - - std::string tag = std::string(username) + ":" + std::string(password); - std::string encoded; - Toolbox::EncodeBase64(encoded, tag); - registeredUsers_.insert(encoded); - } - - void HttpServer::SetSslEnabled(bool enabled) - { - Stop(); - -#if ORTHANC_ENABLE_SSL == 0 - if (enabled) - { - throw OrthancException(ErrorCode_SslDisabled); - } - else - { - ssl_ = false; - } -#else - ssl_ = enabled; -#endif - } - - - void HttpServer::SetKeepAliveEnabled(bool enabled) - { - Stop(); - keepAlive_ = enabled; - LOG(INFO) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled"); - -#if ORTHANC_ENABLE_MONGOOSE == 1 - if (enabled) - { - LOG(WARNING) << "You should disable HTTP keep alive, as you are using Mongoose"; - } -#endif - } - - - void HttpServer::SetAuthenticationEnabled(bool enabled) - { - Stop(); - authentication_ = enabled; - } - - void HttpServer::SetSslCertificate(const char* path) - { - Stop(); - certificate_ = path; - } - - void HttpServer::SetRemoteAccessAllowed(bool allowed) - { - Stop(); - remoteAllowed_ = allowed; - } - - void HttpServer::SetHttpCompressionEnabled(bool enabled) - { - Stop(); - httpCompression_ = enabled; - LOG(WARNING) << "HTTP compression is " << (enabled ? "enabled" : "disabled"); - } - - void HttpServer::SetIncomingHttpRequestFilter(IIncomingHttpRequestFilter& filter) - { - Stop(); - filter_ = &filter; - } - - - void HttpServer::SetHttpExceptionFormatter(IHttpExceptionFormatter& formatter) - { - Stop(); - exceptionFormatter_ = &formatter; - } - - - bool HttpServer::IsValidBasicHttpAuthentication(const std::string& basic) const - { - return registeredUsers_.find(basic) != registeredUsers_.end(); - } - - - void HttpServer::Register(IHttpHandler& handler) - { - Stop(); - handler_ = &handler; - } - - - IHttpHandler& HttpServer::GetHandler() const - { - if (handler_ == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - return *handler_; - } - - - void HttpServer::SetThreadsCount(unsigned int threads) - { - if (threads <= 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - Stop(); - threadsCount_ = threads; - - LOG(INFO) << "The embedded HTTP server will use " << threads << " threads"; - } - - - void HttpServer::SetTcpNoDelay(bool tcpNoDelay) - { - Stop(); - tcpNoDelay_ = tcpNoDelay; - LOG(INFO) << "TCP_NODELAY for the HTTP sockets is set to " - << (tcpNoDelay ? "true" : "false"); - } - - - void HttpServer::SetRequestTimeout(unsigned int seconds) - { - if (seconds <= 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Request timeout must be a stricly positive integer"); - } - - Stop(); - requestTimeout_ = seconds; - LOG(INFO) << "Request timeout in the HTTP server is set to " << seconds << " seconds"; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpServer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,227 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_MONGOOSE) -# error Macro ORTHANC_ENABLE_MONGOOSE must be defined to include this file -#endif - -#if !defined(ORTHANC_ENABLE_CIVETWEB) -# error Macro ORTHANC_ENABLE_CIVETWEB must be defined to include this file -#endif - -#if (ORTHANC_ENABLE_MONGOOSE == 0 && \ - ORTHANC_ENABLE_CIVETWEB == 0) -# error Either ORTHANC_ENABLE_MONGOOSE or ORTHANC_ENABLE_CIVETWEB must be set to 1 -#endif - - -#include "IIncomingHttpRequestFilter.h" - -#include -#include -#include -#include -#include - -namespace Orthanc -{ - class ChunkStore; - class OrthancException; - - class IHttpExceptionFormatter : public boost::noncopyable - { - public: - virtual ~IHttpExceptionFormatter() - { - } - - virtual void Format(HttpOutput& output, - const OrthancException& exception, - HttpMethod method, - const char* uri) = 0; - }; - - - class HttpServer - { - private: - // http://stackoverflow.com/questions/311166/stdauto-ptr-or-boostshared-ptr-for-pimpl-idiom - struct PImpl; - boost::shared_ptr pimpl_; - - IHttpHandler *handler_; - - typedef std::set RegisteredUsers; - RegisteredUsers registeredUsers_; - - bool remoteAllowed_; - bool authentication_; - bool ssl_; - std::string certificate_; - uint16_t port_; - IIncomingHttpRequestFilter* filter_; - bool keepAlive_; - bool httpCompression_; - IHttpExceptionFormatter* exceptionFormatter_; - std::string realm_; - unsigned int threadsCount_; - bool tcpNoDelay_; - unsigned int requestTimeout_; // In seconds - - bool IsRunning() const; - - public: - HttpServer(); - - ~HttpServer(); - - void SetPortNumber(uint16_t port); - - uint16_t GetPortNumber() const - { - return port_; - } - - void Start(); - - void Stop(); - - void ClearUsers(); - - void RegisterUser(const char* username, - const char* password); - - bool IsAuthenticationEnabled() const - { - return authentication_; - } - - void SetAuthenticationEnabled(bool enabled); - - bool IsSslEnabled() const - { - return ssl_; - } - - void SetSslEnabled(bool enabled); - - bool IsKeepAliveEnabled() const - { - return keepAlive_; - } - - void SetKeepAliveEnabled(bool enabled); - - const std::string& GetSslCertificate() const - { - return certificate_; - } - - void SetSslCertificate(const char* path); - - bool IsRemoteAccessAllowed() const - { - return remoteAllowed_; - } - - void SetRemoteAccessAllowed(bool allowed); - - bool IsHttpCompressionEnabled() const - { - return httpCompression_;; - } - - void SetHttpCompressionEnabled(bool enabled); - - IIncomingHttpRequestFilter* GetIncomingHttpRequestFilter() const - { - return filter_; - } - - void SetIncomingHttpRequestFilter(IIncomingHttpRequestFilter& filter); - - ChunkStore& GetChunkStore(); - - bool IsValidBasicHttpAuthentication(const std::string& basic) const; - - void Register(IHttpHandler& handler); - - bool HasHandler() const - { - return handler_ != NULL; - } - - IHttpHandler& GetHandler() const; - - void SetHttpExceptionFormatter(IHttpExceptionFormatter& formatter); - - IHttpExceptionFormatter* GetExceptionFormatter() - { - return exceptionFormatter_; - } - - const std::string& GetRealm() const - { - return realm_; - } - - void SetRealm(const std::string& realm) - { - realm_ = realm; - } - - void SetThreadsCount(unsigned int threads); - - unsigned int GetThreadsCount() const - { - return threadsCount_; - } - - // New in Orthanc 1.5.2, not available for Mongoose - void SetTcpNoDelay(bool tcpNoDelay); - - bool IsTcpNoDelay() const - { - return tcpNoDelay_; - } - - void SetRequestTimeout(unsigned int seconds); - - unsigned int GetRequestTimeout() const - { - return requestTimeout_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,251 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "HttpStreamTranscoder.h" - -#include "../OrthancException.h" -#include "../Compression/ZlibCompressor.h" - -#include // For memcpy() -#include - -#include - -namespace Orthanc -{ - void HttpStreamTranscoder::ReadSource(std::string& buffer) - { - if (source_.SetupHttpCompression(false, false) != HttpCompression_None) - { - throw OrthancException(ErrorCode_InternalError); - } - - uint64_t size = source_.GetContentLength(); - if (static_cast(static_cast(size)) != size) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - buffer.resize(static_cast(size)); - size_t offset = 0; - - while (source_.ReadNextChunk()) - { - size_t chunkSize = static_cast(source_.GetChunkSize()); - memcpy(&buffer[offset], source_.GetChunkContent(), chunkSize); - offset += chunkSize; - } - - if (offset != size) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - HttpCompression HttpStreamTranscoder::SetupZlibCompression(bool deflateAllowed) - { - uint64_t size = source_.GetContentLength(); - - if (size == 0) - { - return HttpCompression_None; - } - - if (size < sizeof(uint64_t)) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - - if (deflateAllowed) - { - bytesToSkip_ = sizeof(uint64_t); - - return HttpCompression_Deflate; - } - else - { - // TODO Use stream-based zlib decoding to reduce memory usage - std::string compressed; - ReadSource(compressed); - - uncompressed_.reset(new BufferHttpSender); - - ZlibCompressor compressor; - IBufferCompressor::Uncompress(uncompressed_->GetBuffer(), compressor, compressed); - - return HttpCompression_None; - } - } - - - HttpCompression HttpStreamTranscoder::SetupHttpCompression(bool gzipAllowed, - bool deflateAllowed) - { - if (ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - ready_ = true; - - switch (sourceCompression_) - { - case CompressionType_None: - return HttpCompression_None; - - case CompressionType_ZlibWithSize: - return SetupZlibCompression(deflateAllowed); - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - uint64_t HttpStreamTranscoder::GetContentLength() - { - if (!ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (uncompressed_.get() != NULL) - { - return uncompressed_->GetContentLength(); - } - else - { - uint64_t length = source_.GetContentLength(); - if (length < bytesToSkip_) - { - throw OrthancException(ErrorCode_InternalError); - } - - return length - bytesToSkip_; - } - } - - - bool HttpStreamTranscoder::ReadNextChunk() - { - if (!ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (uncompressed_.get() != NULL) - { - return uncompressed_->ReadNextChunk(); - } - - assert(skipped_ <= bytesToSkip_); - if (skipped_ == bytesToSkip_) - { - // We have already skipped the first bytes of the stream - currentChunkOffset_ = 0; - return source_.ReadNextChunk(); - } - - // This condition can only be true on the first call to "ReadNextChunk()" - for (;;) - { - assert(skipped_ < bytesToSkip_); - - bool ok = source_.ReadNextChunk(); - if (!ok) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - - size_t remaining = static_cast(bytesToSkip_ - skipped_); - size_t s = source_.GetChunkSize(); - - if (s < remaining) - { - skipped_ += s; - } - else if (s == remaining) - { - // We have skipped enough bytes, but we must read a new chunk - currentChunkOffset_ = 0; - skipped_ = bytesToSkip_; - return source_.ReadNextChunk(); - } - else - { - // We have skipped enough bytes, and we have enough data in the current chunk - assert(s > remaining); - currentChunkOffset_ = remaining; - skipped_ = bytesToSkip_; - return true; - } - } - } - - - const char* HttpStreamTranscoder::GetChunkContent() - { - if (!ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (uncompressed_.get() != NULL) - { - return uncompressed_->GetChunkContent(); - } - else - { - return source_.GetChunkContent() + currentChunkOffset_; - } - } - - size_t HttpStreamTranscoder::GetChunkSize() - { - if (!ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (uncompressed_.get() != NULL) - { - return uncompressed_->GetChunkSize(); - } - else - { - return static_cast(source_.GetChunkSize() - currentChunkOffset_); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpStreamTranscoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "BufferHttpSender.h" - -#include "../Compatibility.h" - -#include // For std::unique_ptr - -namespace Orthanc -{ - class HttpStreamTranscoder : public IHttpStreamAnswer - { - private: - IHttpStreamAnswer& source_; - CompressionType sourceCompression_; - uint64_t bytesToSkip_; - uint64_t skipped_; - uint64_t currentChunkOffset_; - bool ready_; - - std::unique_ptr uncompressed_; - - void ReadSource(std::string& buffer); - - HttpCompression SetupZlibCompression(bool deflateAllowed); - - public: - HttpStreamTranscoder(IHttpStreamAnswer& source, - CompressionType compression) : - source_(source), - sourceCompression_(compression), - bytesToSkip_(0), - skipped_(0), - currentChunkOffset_(0), - ready_(false) - { - } - - // This is the first method to be called - virtual HttpCompression SetupHttpCompression(bool gzipAllowed, - bool deflateAllowed); - - virtual bool HasContentFilename(std::string& filename) - { - return source_.HasContentFilename(filename); - } - - virtual std::string GetContentType() - { - return source_.GetContentType(); - } - - virtual uint64_t GetContentLength(); - - virtual bool ReadNextChunk(); - - virtual const char* GetChunkContent(); - - virtual size_t GetChunkSize(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,298 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "HttpToolbox.h" - -#include -#include -#include - -#include "HttpOutput.h" -#include "StringHttpOutput.h" - - -static const char* LOCALHOST = "127.0.0.1"; - - - -namespace Orthanc -{ - static void SplitGETNameValue(IHttpHandler::GetArguments& result, - const char* start, - const char* end) - { - std::string name, value; - - const char* equal = strchr(start, '='); - if (equal == NULL || equal >= end) - { - name = std::string(start, end - start); - //value = ""; - } - else - { - name = std::string(start, equal - start); - value = std::string(equal + 1, end); - } - - Toolbox::UrlDecode(name); - Toolbox::UrlDecode(value); - - result.push_back(std::make_pair(name, value)); - } - - - void HttpToolbox::ParseGetArguments(IHttpHandler::GetArguments& result, - const char* query) - { - const char* pos = query; - - while (pos != NULL) - { - const char* ampersand = strchr(pos, '&'); - if (ampersand) - { - SplitGETNameValue(result, pos, ampersand); - pos = ampersand + 1; - } - else - { - // No more ampersand, this is the last argument - SplitGETNameValue(result, pos, pos + strlen(pos)); - pos = NULL; - } - } - } - - - void HttpToolbox::ParseGetQuery(UriComponents& uri, - IHttpHandler::GetArguments& getArguments, - const char* query) - { - const char *questionMark = ::strchr(query, '?'); - if (questionMark == NULL) - { - // No question mark in the string - Toolbox::SplitUriComponents(uri, query); - getArguments.clear(); - } - else - { - Toolbox::SplitUriComponents(uri, std::string(query, questionMark)); - HttpToolbox::ParseGetArguments(getArguments, questionMark + 1); - } - } - - - std::string HttpToolbox::GetArgument(const IHttpHandler::Arguments& getArguments, - const std::string& name, - const std::string& defaultValue) - { - IHttpHandler::Arguments::const_iterator it = getArguments.find(name); - if (it == getArguments.end()) - { - return defaultValue; - } - else - { - return it->second; - } - } - - - std::string HttpToolbox::GetArgument(const IHttpHandler::GetArguments& getArguments, - const std::string& name, - const std::string& defaultValue) - { - for (size_t i = 0; i < getArguments.size(); i++) - { - if (getArguments[i].first == name) - { - return getArguments[i].second; - } - } - - return defaultValue; - } - - - - void HttpToolbox::ParseCookies(IHttpHandler::Arguments& result, - const IHttpHandler::Arguments& httpHeaders) - { - result.clear(); - - IHttpHandler::Arguments::const_iterator it = httpHeaders.find("cookie"); - if (it != httpHeaders.end()) - { - const std::string& cookies = it->second; - - size_t pos = 0; - while (pos != std::string::npos) - { - size_t nextSemicolon = cookies.find(";", pos); - std::string cookie; - - if (nextSemicolon == std::string::npos) - { - cookie = cookies.substr(pos); - pos = std::string::npos; - } - else - { - cookie = cookies.substr(pos, nextSemicolon - pos); - pos = nextSemicolon + 1; - } - - size_t equal = cookie.find("="); - if (equal != std::string::npos) - { - std::string name = Toolbox::StripSpaces(cookie.substr(0, equal)); - std::string value = Toolbox::StripSpaces(cookie.substr(equal + 1)); - result[name] = value; - } - } - } - } - - - void HttpToolbox::CompileGetArguments(IHttpHandler::Arguments& compiled, - const IHttpHandler::GetArguments& source) - { - compiled.clear(); - - for (size_t i = 0; i < source.size(); i++) - { - compiled[source[i].first] = source[i].second; - } - } - - - bool HttpToolbox::SimpleGet(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const IHttpHandler::Arguments& httpHeaders) - { - UriComponents curi; - IHttpHandler::GetArguments getArguments; - ParseGetQuery(curi, getArguments, uri.c_str()); - - StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); - - if (handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Get, curi, - httpHeaders, getArguments, NULL /* no body for GET */, 0)) - { - stream.GetOutput(result); - return true; - } - else - { - return false; - } - } - - - static bool SimplePostOrPut(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - HttpMethod method, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const IHttpHandler::Arguments& httpHeaders) - { - IHttpHandler::GetArguments getArguments; // No GET argument for POST/PUT - - UriComponents curi; - Toolbox::SplitUriComponents(curi, uri); - - StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); - - if (handler.Handle(http, origin, LOCALHOST, "", method, curi, - httpHeaders, getArguments, bodyData, bodySize)) - { - stream.GetOutput(result); - return true; - } - else - { - return false; - } - } - - - bool HttpToolbox::SimplePost(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const IHttpHandler::Arguments& httpHeaders) - { - return SimplePostOrPut(result, handler, origin, HttpMethod_Post, uri, bodyData, bodySize, httpHeaders); - } - - - bool HttpToolbox::SimplePut(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const IHttpHandler::Arguments& httpHeaders) - { - return SimplePostOrPut(result, handler, origin, HttpMethod_Put, uri, bodyData, bodySize, httpHeaders); - } - - - bool HttpToolbox::SimpleDelete(IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const IHttpHandler::Arguments& httpHeaders) - { - UriComponents curi; - Toolbox::SplitUriComponents(curi, uri); - - IHttpHandler::GetArguments getArguments; // No GET argument for DELETE - - StringHttpOutput stream; - HttpOutput http(stream, false /* no keep alive */); - - return handler.Handle(http, origin, LOCALHOST, "", HttpMethod_Delete, curi, - httpHeaders, getArguments, NULL /* no body for DELETE */, 0); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/HttpToolbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IHttpHandler.h" - -namespace Orthanc -{ - class HttpToolbox - { - public: - static void ParseGetArguments(IHttpHandler::GetArguments& result, - const char* query); - - static void ParseGetQuery(UriComponents& uri, - IHttpHandler::GetArguments& getArguments, - const char* query); - - static std::string GetArgument(const IHttpHandler::Arguments& getArguments, - const std::string& name, - const std::string& defaultValue); - - static std::string GetArgument(const IHttpHandler::GetArguments& getArguments, - const std::string& name, - const std::string& defaultValue); - - static void ParseCookies(IHttpHandler::Arguments& result, - const IHttpHandler::Arguments& httpHeaders); - - static void CompileGetArguments(IHttpHandler::Arguments& compiled, - const IHttpHandler::GetArguments& source); - - static bool SimpleGet(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const IHttpHandler::Arguments& httpHeaders); - - static bool SimplePost(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const IHttpHandler::Arguments& httpHeaders); - - static bool SimplePut(std::string& result, - IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const void* bodyData, - size_t bodySize, - const IHttpHandler::Arguments& httpHeaders); - - static bool SimpleDelete(IHttpHandler& handler, - RequestOrigin origin, - const std::string& uri, - const IHttpHandler::Arguments& httpHeaders); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Compatibility.h" -#include "../Toolbox.h" -#include "HttpOutput.h" - -#include -#include -#include -#include -#include - -namespace Orthanc -{ - class IHttpHandler : public boost::noncopyable - { - public: - typedef std::map Arguments; - typedef std::vector< std::pair > GetArguments; - - - class IChunkedRequestReader : public boost::noncopyable - { - public: - virtual ~IChunkedRequestReader() - { - } - - virtual void AddBodyChunk(const void* data, - size_t size) = 0; - - virtual void Execute(HttpOutput& output) = 0; - }; - - - virtual ~IHttpHandler() - { - } - - /** - * This function allows to deal with chunked transfers (new in - * Orthanc 1.5.7). It is only called if "method" is POST or PUT. - **/ - virtual bool CreateChunkedRequestReader(std::unique_ptr& target, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers) = 0; - - virtual bool Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpOutputStream.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpOutputStream.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpOutputStream.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpOutputStream.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include -#include - -namespace Orthanc -{ - class IHttpOutputStream : public boost::noncopyable - { - public: - virtual ~IHttpOutputStream() - { - } - - virtual void OnHttpStatusReceived(HttpStatus status) = 0; - - virtual void Send(bool isHeader, const void* buffer, size_t length) = 0; - - // Disable HTTP keep alive for this single HTTP connection. Must - // be called before sending the "HTTP/1.1 200 OK" header. - virtual void DisableKeepAlive() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpStreamAnswer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpStreamAnswer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpStreamAnswer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IHttpStreamAnswer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include -#include -#include - -namespace Orthanc -{ - class IHttpStreamAnswer : public boost::noncopyable - { - public: - virtual ~IHttpStreamAnswer() - { - } - - // This is the first method to be called - virtual HttpCompression SetupHttpCompression(bool gzipAllowed, - bool deflateAllowed) = 0; - - virtual bool HasContentFilename(std::string& filename) = 0; - - virtual std::string GetContentType() = 0; - - virtual uint64_t GetContentLength() = 0; - - virtual bool ReadNextChunk() = 0; - - virtual const char* GetChunkContent() = 0; - - virtual size_t GetChunkSize() = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IIncomingHttpRequestFilter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IIncomingHttpRequestFilter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IIncomingHttpRequestFilter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/IIncomingHttpRequestFilter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IHttpHandler.h" - -namespace Orthanc -{ - class IIncomingHttpRequestFilter : public boost::noncopyable - { - public: - virtual ~IIncomingHttpRequestFilter() - { - } - - virtual bool IsAllowed(HttpMethod method, - const char* uri, - const char* ip, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::GetArguments& getArguments) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,357 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "MultipartStreamReader.h" - -#include "../OrthancException.h" -#include "../Toolbox.h" - -#include - -#if defined(_MSC_VER) -# include // Definition of ssize_t -#endif - -namespace Orthanc -{ - static void ParseHeaders(MultipartStreamReader::HttpHeaders& headers, - StringMatcher::Iterator start, - StringMatcher::Iterator end) - { - std::string tmp(start, end); - - std::vector lines; - Toolbox::TokenizeString(lines, tmp, '\n'); - - headers.clear(); - - for (size_t i = 0; i < lines.size(); i++) - { - size_t separator = lines[i].find(':'); - if (separator != std::string::npos) - { - std::string key = Toolbox::StripSpaces(lines[i].substr(0, separator)); - std::string value = Toolbox::StripSpaces(lines[i].substr(separator + 1)); - - Toolbox::ToLowerCase(key); - headers[key] = value; - } - } - } - - - static bool LookupHeaderSizeValue(size_t& target, - const MultipartStreamReader::HttpHeaders& headers, - const std::string& key) - { - MultipartStreamReader::HttpHeaders::const_iterator it = headers.find(key); - if (it == headers.end()) - { - return false; - } - else - { - int64_t value; - - try - { - value = boost::lexical_cast(it->second); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (value < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - target = static_cast(value); - return true; - } - } - } - - - void MultipartStreamReader::ParseStream() - { - if (handler_ == NULL || - state_ == State_Done) - { - return; - } - - std::string corpus; - buffer_.Flatten(corpus); - - StringMatcher::Iterator current = corpus.begin(); - StringMatcher::Iterator corpusEnd = corpus.end(); - - if (state_ == State_UnusedArea) - { - /** - * "Before the first boundary is an area that is ignored by - * MIME-compliant clients. This area is generally used to put - * a message to users of old non-MIME clients." - * https://en.wikipedia.org/wiki/MIME#Multipart_messages - **/ - - if (boundaryMatcher_.Apply(current, corpusEnd)) - { - current = boundaryMatcher_.GetMatchBegin(); - state_ = State_Content; - } - else - { - // We have not seen the end of the unused area yet - std::string reminder(current, corpusEnd); - buffer_.AddChunkDestructive(reminder); - return; - } - } - - for (;;) - { - size_t patternSize = boundaryMatcher_.GetPattern().size(); - size_t remainingSize = std::distance(current, corpusEnd); - if (remainingSize < patternSize + 2) - { - break; // Not enough data available - } - - std::string boundary(current, current + patternSize + 2); - if (boundary == boundaryMatcher_.GetPattern() + "--") - { - state_ = State_Done; - return; - } - - if (boundary != boundaryMatcher_.GetPattern() + "\r\n") - { - throw OrthancException(ErrorCode_NetworkProtocol, - "Garbage between two items in a multipart stream"); - } - - StringMatcher::Iterator start = current + patternSize + 2; - - if (!headersMatcher_.Apply(start, corpusEnd)) - { - break; // Not enough data available - } - - HttpHeaders headers; - ParseHeaders(headers, start, headersMatcher_.GetMatchBegin()); - - size_t contentLength = 0; - if (!LookupHeaderSizeValue(contentLength, headers, "content-length")) - { - if (boundaryMatcher_.Apply(headersMatcher_.GetMatchEnd(), corpusEnd)) - { - size_t d = std::distance(headersMatcher_.GetMatchEnd(), boundaryMatcher_.GetMatchBegin()); - if (d <= 1) - { - throw OrthancException(ErrorCode_NetworkProtocol); - } - else - { - contentLength = d - 2; - } - } - else - { - break; // Not enough data available to have a full part - } - } - - // Explicit conversion to avoid warning about signed vs. unsigned comparison - std::iterator_traits::difference_type d = contentLength + 2; - if (d > std::distance(headersMatcher_.GetMatchEnd(), corpusEnd)) - { - break; // Not enough data available to have a full part - } - - const char* p = headersMatcher_.GetPointerEnd() + contentLength; - if (p[0] != '\r' || - p[1] != '\n') - { - throw OrthancException(ErrorCode_NetworkProtocol, - "No endline at the end of a part"); - } - - handler_->HandlePart(headers, headersMatcher_.GetPointerEnd(), contentLength); - current = headersMatcher_.GetMatchEnd() + contentLength + 2; - } - - if (current != corpusEnd) - { - std::string reminder(current, corpusEnd); - buffer_.AddChunkDestructive(reminder); - } - } - - - MultipartStreamReader::MultipartStreamReader(const std::string& boundary) : - state_(State_UnusedArea), - handler_(NULL), - headersMatcher_("\r\n\r\n"), - boundaryMatcher_("--" + boundary), - blockSize_(10 * 1024 * 1024) - { - } - - - void MultipartStreamReader::SetBlockSize(size_t size) - { - if (size == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - blockSize_ = size; - } - } - - - void MultipartStreamReader::AddChunk(const void* chunk, - size_t size) - { - if (state_ != State_Done && - size != 0) - { - size_t oldSize = buffer_.GetNumBytes(); - - buffer_.AddChunk(chunk, size); - - if (oldSize / blockSize_ != buffer_.GetNumBytes() / blockSize_) - { - ParseStream(); - } - } - } - - - void MultipartStreamReader::AddChunk(const std::string& chunk) - { - if (!chunk.empty()) - { - AddChunk(chunk.c_str(), chunk.size()); - } - } - - - void MultipartStreamReader::CloseStream() - { - if (buffer_.GetNumBytes() != 0) - { - ParseStream(); - } - } - - - bool MultipartStreamReader::GetMainContentType(std::string& contentType, - const HttpHeaders& headers) - { - HttpHeaders::const_iterator it = headers.find("content-type"); - - if (it == headers.end()) - { - return false; - } - else - { - contentType = it->second; - return true; - } - } - - - bool MultipartStreamReader::ParseMultipartContentType(std::string& contentType, - std::string& subType, - std::string& boundary, - const std::string& contentTypeHeader) - { - std::vector tokens; - Orthanc::Toolbox::TokenizeString(tokens, contentTypeHeader, ';'); - - if (tokens.empty()) - { - return false; - } - - contentType = Orthanc::Toolbox::StripSpaces(tokens[0]); - Orthanc::Toolbox::ToLowerCase(contentType); - - if (contentType.empty()) - { - return false; - } - - bool valid = false; - subType.clear(); - - for (size_t i = 0; i < tokens.size(); i++) - { - std::vector items; - Orthanc::Toolbox::TokenizeString(items, tokens[i], '='); - - if (items.size() == 2) - { - if (boost::iequals("boundary", Orthanc::Toolbox::StripSpaces(items[0]))) - { - boundary = Orthanc::Toolbox::StripSpaces(items[1]); - valid = !boundary.empty(); - } - else if (boost::iequals("type", Orthanc::Toolbox::StripSpaces(items[0]))) - { - subType = Orthanc::Toolbox::StripSpaces(items[1]); - Orthanc::Toolbox::ToLowerCase(subType); - - // https://bitbucket.org/sjodogne/orthanc/issues/54/decide-what-to-do-wrt-quoting-of-multipart - // https://tools.ietf.org/html/rfc7231#section-3.1.1.1 - if (subType.size() >= 2 && - subType[0] == '"' && - subType[subType.size() - 1] == '"') - { - subType = subType.substr(1, subType.size() - 2); - } - } - } - } - - return valid; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/MultipartStreamReader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,107 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "StringMatcher.h" -#include "../ChunkedBuffer.h" - -#include - -namespace Orthanc -{ - class MultipartStreamReader : public boost::noncopyable - { - public: - typedef std::map HttpHeaders; - - class IHandler : public boost::noncopyable - { - public: - virtual ~IHandler() - { - } - - virtual void HandlePart(const HttpHeaders& headers, - const void* part, - size_t size) = 0; - }; - - private: - enum State - { - State_UnusedArea, - State_Content, - State_Done - }; - - State state_; - IHandler* handler_; - StringMatcher headersMatcher_; - StringMatcher boundaryMatcher_; - ChunkedBuffer buffer_; - size_t blockSize_; - - void ParseStream(); - - public: - MultipartStreamReader(const std::string& boundary); - - void SetBlockSize(size_t size); - - size_t GetBlockSize() const - { - return blockSize_; - } - - void SetHandler(IHandler& handler) - { - handler_ = &handler; - } - - void AddChunk(const void* chunk, - size_t size); - - void AddChunk(const std::string& chunk); - - void CloseStream(); - - static bool GetMainContentType(std::string& contentType, - const HttpHeaders& headers); - - static bool ParseMultipartContentType(std::string& contentType, - std::string& subType, // Possibly empty - std::string& boundary, - const std::string& contentTypeHeader); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "StringHttpOutput.h" - -#include "../OrthancException.h" - -namespace Orthanc -{ - void StringHttpOutput::OnHttpStatusReceived(HttpStatus status) - { - switch (status) - { - case HttpStatus_200_Ok: - found_ = true; - break; - - case HttpStatus_404_NotFound: - found_ = false; - break; - - default: - throw OrthancException(ErrorCode_BadRequest); - } - } - - void StringHttpOutput::Send(bool isHeader, const void* buffer, size_t length) - { - if (!isHeader) - { - buffer_.AddChunk(buffer, length); - } - } - - void StringHttpOutput::GetOutput(std::string& output) - { - if (found_) - { - buffer_.Flatten(output); - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringHttpOutput.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IHttpOutputStream.h" - -#include "../ChunkedBuffer.h" - -namespace Orthanc -{ - class StringHttpOutput : public IHttpOutputStream - { - private: - bool found_; - ChunkedBuffer buffer_; - - public: - StringHttpOutput() : found_(false) - { - } - - virtual void OnHttpStatusReceived(HttpStatus status); - - virtual void Send(bool isHeader, const void* buffer, size_t length); - - virtual void DisableKeepAlive() - { - } - - void GetOutput(std::string& output); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "StringMatcher.h" - -#include "../OrthancException.h" - -#include -//#include -//#include - -namespace Orthanc -{ - class StringMatcher::Search - { - private: - typedef boost::algorithm::boyer_moore Algorithm; - //typedef boost::algorithm::boyer_moore_horspool Algorithm; - - Algorithm algorithm_; - - public: - // WARNING - The lifetime of "pattern_" must be larger than - // "search_", as the latter internally keeps a pointer to "pattern" (*) - Search(const std::string& pattern) : - algorithm_(pattern.begin(), pattern.end()) - { - } - - Iterator Apply(Iterator start, - Iterator end) const - { -#if BOOST_VERSION >= 106200 - return algorithm_(start, end).first; -#else - return algorithm_(start, end); -#endif - } - }; - - - StringMatcher::StringMatcher(const std::string& pattern) : - pattern_(pattern), - valid_(false) - { - // WARNING - Don't use "pattern" (local variable, will be - // destroyed once exiting the constructor) but "pattern_" - // (variable member, will last as long as the algorithm), - // otherwise lifetime is bad! (*) - search_.reset(new Search(pattern_)); - } - - - bool StringMatcher::Apply(Iterator start, - Iterator end) - { - assert(search_.get() != NULL); - matchBegin_ = search_->Apply(start, end); - - if (matchBegin_ == end) - { - valid_ = false; - } - else - { - matchEnd_ = matchBegin_ + pattern_.size(); - assert(matchEnd_ <= end); - valid_ = true; - } - - return valid_; - } - - - StringMatcher::Iterator StringMatcher::GetMatchBegin() const - { - if (valid_) - { - return matchBegin_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - StringMatcher::Iterator StringMatcher::GetMatchEnd() const - { - if (valid_) - { - return matchEnd_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - const char* StringMatcher::GetPointerBegin() const - { - return &GetMatchBegin()[0]; - } - - - const char* StringMatcher::GetPointerEnd() const - { - return GetPointerBegin() + pattern_.size(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/HttpServer/StringMatcher.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include -#include - -namespace Orthanc -{ - // Convenience class that wraps a Boost algorithm for string matching - class StringMatcher : public boost::noncopyable - { - public: - typedef std::string::const_iterator Iterator; - - private: - class Search; - - boost::shared_ptr search_; // PImpl pattern - std::string pattern_; - bool valid_; - Iterator matchBegin_; - Iterator matchEnd_; - - public: - StringMatcher(const std::string& pattern); - - const std::string& GetPattern() const - { - return pattern_; - } - - bool IsValid() const - { - return valid_; - } - - bool Apply(Iterator start, - Iterator end); - - bool Apply(const std::string& corpus) - { - return Apply(corpus.begin(), corpus.end()); - } - - Iterator GetMatchBegin() const; - - Iterator GetMatchEnd() const; - - const char* GetPointerBegin() const; - - const char* GetPointerEnd() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/IDynamicObject.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/IDynamicObject.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/IDynamicObject.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/IDynamicObject.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include - -namespace Orthanc -{ - /** - * This class should be the ancestor to any class whose type is - * determined at the runtime, and that can be dynamically allocated. - * Being a child of IDynamicObject only implies the existence of a - * virtual destructor. - **/ - class IDynamicObject : public boost::noncopyable - { - public: - virtual ~IDynamicObject() - { - } - }; - - - /** - * This class is a simple implementation of a IDynamicObject that - * stores a single typed value. - */ - template - class SingleValueObject : public IDynamicObject - { - private: - T value_; - - public: - explicit SingleValueObject(const T& value) : - value_(value) - { - } - - const T& GetValue() const - { - return value_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,429 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "Font.h" - -#if !defined(ORTHANC_ENABLE_LOCALE) -# error ORTHANC_ENABLE_LOCALE must be defined to use this file -#endif - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "Image.h" -#include "ImageProcessing.h" - -#include -#include -#include - -namespace Orthanc -{ - Font::~Font() - { - for (Characters::iterator it = characters_.begin(); - it != characters_.end(); ++it) - { - delete it->second; - } - } - - - void Font::LoadFromMemory(const std::string& font) - { - Json::Value v; - Json::Reader reader; - if (!reader.parse(font, v) || - v.type() != Json::objectValue || - !v.isMember("Name") || - !v.isMember("Size") || - !v.isMember("Characters") || - v["Name"].type() != Json::stringValue || - v["Size"].type() != Json::intValue || - v["Characters"].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFont); - } - - name_ = v["Name"].asString(); - size_ = v["Size"].asUInt(); - maxHeight_ = 0; - - Json::Value::Members characters = v["Characters"].getMemberNames(); - - for (size_t i = 0; i < characters.size(); i++) - { - const Json::Value& info = v["Characters"][characters[i]]; - if (info.type() != Json::objectValue || - !info.isMember("Advance") || - !info.isMember("Bitmap") || - !info.isMember("Height") || - !info.isMember("Top") || - !info.isMember("Width") || - info["Advance"].type() != Json::intValue || - info["Bitmap"].type() != Json::arrayValue || - info["Height"].type() != Json::intValue || - info["Top"].type() != Json::intValue || - info["Width"].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadFont); - } - - std::unique_ptr c(new Character); - - c->advance_ = info["Advance"].asUInt(); - c->height_ = info["Height"].asUInt(); - c->top_ = info["Top"].asUInt(); - c->width_ = info["Width"].asUInt(); - c->bitmap_.resize(info["Bitmap"].size()); - - if (c->height_ > maxHeight_) - { - maxHeight_ = c->height_; - } - - for (Json::Value::ArrayIndex j = 0; j < info["Bitmap"].size(); j++) - { - if (info["Bitmap"][j].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadFont); - } - - int value = info["Bitmap"][j].asInt(); - if (value < 0 || value > 255) - { - throw OrthancException(ErrorCode_BadFont); - } - - c->bitmap_[j] = static_cast(value); - } - - int index = boost::lexical_cast(characters[i]); - if (index < 0 || index > 255) - { - throw OrthancException(ErrorCode_BadFont); - } - - characters_[static_cast(index)] = c.release(); - } - } - - -#if ORTHANC_SANDBOXED == 0 - void Font::LoadFromFile(const std::string& path) - { - std::string font; - SystemToolbox::ReadFile(font, path); - LoadFromMemory(font); - } -#endif - - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 - void Font::LoadFromResource(EmbeddedResources::FileResourceId resource) - { - std::string content; - EmbeddedResources::GetFileResource(content, resource); - LoadFromMemory(content); - } -#endif - - - static unsigned int MyMin(unsigned int a, - unsigned int b) - { - return a < b ? a : b; - } - - - void Font::DrawCharacter(ImageAccessor& target, - const Character& character, - int x, - int y, - const uint8_t color[4]) const - { - // Compute the bounds of the character - if (x >= static_cast(target.GetWidth()) || - y >= static_cast(target.GetHeight())) - { - // The character is out of the image - return; - } - - unsigned int left = x < 0 ? -x : 0; - unsigned int top = y < 0 ? -y : 0; - unsigned int width = MyMin(character.width_, target.GetWidth() - x); - unsigned int height = MyMin(character.height_, target.GetHeight() - y); - - unsigned int bpp = target.GetBytesPerPixel(); - - // Blit the font bitmap OVER the target image - // https://en.wikipedia.org/wiki/Alpha_compositing - - for (unsigned int cy = top; cy < height; cy++) - { - uint8_t* p = reinterpret_cast(target.GetRow(y + cy)) + (x + left) * bpp; - unsigned int pos = cy * character.width_ + left; - - switch (target.GetFormat()) - { - case PixelFormat_Grayscale8: - { - assert(bpp == 1); - for (unsigned int cx = left; cx < width; cx++, pos++, p++) - { - uint16_t alpha = character.bitmap_[pos]; - uint16_t value = alpha * static_cast(color[0]) + (255 - alpha) * static_cast(*p); - *p = static_cast(value >> 8); - } - - break; - } - - case PixelFormat_RGB24: - { - assert(bpp == 3); - for (unsigned int cx = left; cx < width; cx++, pos++, p += 3) - { - uint16_t alpha = character.bitmap_[pos]; - for (uint8_t i = 0; i < 3; i++) - { - uint16_t value = alpha * static_cast(color[i]) + (255 - alpha) * static_cast(p[i]); - p[i] = static_cast(value >> 8); - } - } - - break; - } - - case PixelFormat_RGBA32: - case PixelFormat_BGRA32: - { - assert(bpp == 4); - - for (unsigned int cx = left; cx < width; cx++, pos++, p += 4) - { - float alpha = static_cast(character.bitmap_[pos]) / 255.0f; - float beta = (1.0f - alpha) * static_cast(p[3]) / 255.0f; - float denom = 1.0f / (alpha + beta); - - for (uint8_t i = 0; i < 3; i++) - { - p[i] = static_cast((alpha * static_cast(color[i]) + - beta * static_cast(p[i])) * denom); - } - - p[3] = static_cast(255.0f * (alpha + beta)); - } - - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - } - - - void Font::DrawInternal(ImageAccessor& target, - const std::string& utf8, - int x, - int y, - const uint8_t color[4]) const - { - if (target.GetFormat() != PixelFormat_Grayscale8 && - target.GetFormat() != PixelFormat_RGB24 && - target.GetFormat() != PixelFormat_RGBA32 && - target.GetFormat() != PixelFormat_BGRA32) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - int a = x; - -#if ORTHANC_ENABLE_LOCALE == 1 - std::string s = Toolbox::ConvertFromUtf8(utf8, Encoding_Latin1); -#else - // If the locale support is disabled, simply drop non-ASCII - // characters from the source UTF-8 string - std::string s = Toolbox::ConvertToAscii(utf8); -#endif - - for (size_t i = 0; i < s.size(); i++) - { - if (s[i] == '\n') - { - // Go to the next line - a = x; - y += maxHeight_ + 1; - } - else - { - Characters::const_iterator c = characters_.find(s[i]); - if (c != characters_.end()) - { - DrawCharacter(target, *c->second, a, y + static_cast(c->second->top_), color); - a += c->second->advance_; - } - } - } - } - - - void Font::Draw(ImageAccessor& target, - const std::string& utf8, - int x, - int y, - uint8_t grayscale) const - { - uint8_t color[4] = { grayscale, grayscale, grayscale, 255 }; - DrawInternal(target, utf8, x, y, color); - } - - - void Font::Draw(ImageAccessor& target, - const std::string& utf8, - int x, - int y, - uint8_t r, - uint8_t g, - uint8_t b) const - { - uint8_t color[4]; - - switch (target.GetFormat()) - { - case PixelFormat_BGRA32: - color[0] = b; - color[1] = g; - color[2] = r; - color[3] = 255; - break; - - default: - color[0] = r; - color[1] = g; - color[2] = b; - color[3] = 255; - break; - } - - DrawInternal(target, utf8, x, y, color); - } - - - void Font::ComputeTextExtent(unsigned int& width, - unsigned int& height, - const std::string& utf8) const - { - width = 0; - height = 0; - -#if ORTHANC_ENABLE_LOCALE == 1 - std::string s = Toolbox::ConvertFromUtf8(utf8, Encoding_Latin1); -#else - // If the locale support is disabled, simply drop non-ASCII - // characters from the source UTF-8 string - std::string s = Toolbox::ConvertToAscii(utf8); -#endif - - // Compute the text extent - unsigned int x = 0; - unsigned int y = 0; - - for (size_t i = 0; i < s.size(); i++) - { - if (s[i] == '\n') - { - // Go to the next line - x = 0; - y += (maxHeight_ + 1); - } - else - { - Characters::const_iterator c = characters_.find(s[i]); - if (c != characters_.end()) - { - x += c->second->advance_; - - unsigned int bottom = y + c->second->top_ + c->second->height_; - if (bottom > height) - { - height = bottom; - } - - if (x > width) - { - width = x; - } - } - } - } - } - - - ImageAccessor* Font::Render(const std::string& utf8, - PixelFormat format, - uint8_t r, - uint8_t g, - uint8_t b) const - { - unsigned int width, height; - ComputeTextExtent(width, height, utf8); - - std::unique_ptr target(new Image(format, width, height, false)); - ImageProcessing::Set(*target, 0, 0, 0, 255); - Draw(*target, utf8, 0, 0, r, g, b); - - return target.release(); - } - - - ImageAccessor* Font::RenderAlpha(const std::string& utf8) const - { - unsigned int width, height; - ComputeTextExtent(width, height, utf8); - - std::unique_ptr target(new Image(PixelFormat_Grayscale8, width, height, false)); - ImageProcessing::Set(*target, 0); - Draw(*target, utf8, 0, 0, 255); - - return target.release(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Font.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,139 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES) -# error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined -#endif - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 -# include // Autogenerated file -#endif - -#include "ImageAccessor.h" - -#include -#include -#include -#include - -namespace Orthanc -{ - class Font : public boost::noncopyable - { - private: - struct Character - { - unsigned int width_; - unsigned int height_; - unsigned int top_; - unsigned int advance_; - std::vector bitmap_; - }; - - typedef std::map Characters; - - std::string name_; - unsigned int size_; - Characters characters_; - unsigned int maxHeight_; - - void DrawCharacter(ImageAccessor& target, - const Character& character, - int x, - int y, - const uint8_t color[4]) const; - - void DrawInternal(ImageAccessor& target, - const std::string& utf8, - int x, - int y, - const uint8_t color[4]) const; - - public: - Font() : - size_(0), - maxHeight_(0) - { - } - - ~Font(); - - void LoadFromMemory(const std::string& font); - -#if ORTHANC_SANDBOXED == 0 - void LoadFromFile(const std::string& path); -#endif - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 - void LoadFromResource(EmbeddedResources::FileResourceId resource); -#endif - - const std::string& GetName() const - { - return name_; - } - - unsigned int GetSize() const - { - return size_; - } - - void Draw(ImageAccessor& target, - const std::string& utf8, - int x, - int y, - uint8_t grayscale) const; - - void Draw(ImageAccessor& target, - const std::string& utf8, - int x, - int y, - uint8_t r, - uint8_t g, - uint8_t b) const; - - void ComputeTextExtent(unsigned int& width, - unsigned int& height, - const std::string& utf8) const; - - ImageAccessor* Render(const std::string& utf8, - PixelFormat format, - uint8_t r, - uint8_t g, - uint8_t b) const; - - ImageAccessor* RenderAlpha(const std::string& utf8) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "FontRegistry.h" - -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - FontRegistry::~FontRegistry() - { - for (Fonts::iterator it = fonts_.begin(); it != fonts_.end(); ++it) - { - delete *it; - } - } - - - void FontRegistry::AddFromMemory(const std::string& font) - { - std::unique_ptr f(new Font); - f->LoadFromMemory(font); - fonts_.push_back(f.release()); - } - - -#if ORTHANC_SANDBOXED == 0 - void FontRegistry::AddFromFile(const std::string& path) - { - std::unique_ptr f(new Font); - f->LoadFromFile(path); - fonts_.push_back(f.release()); - } -#endif - - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 - void FontRegistry::AddFromResource(EmbeddedResources::FileResourceId resource) - { - std::string content; - EmbeddedResources::GetFileResource(content, resource); - AddFromMemory(content); - } -#endif - - - const Font& FontRegistry::GetFont(size_t i) const - { - if (i >= fonts_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return *fonts_[i]; - } - } - - const Font* FontRegistry::FindFont(const std::string& fontName) const - { - for (Fonts::const_iterator it = fonts_.begin(); it != fonts_.end(); it++) - { - if ((*it)->GetName() == fontName) - { - return *it; - } - } - - return NULL; - } - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/FontRegistry.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "Font.h" - -#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES) -# error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined -#endif - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 -# include // Autogenerated file -#endif - -namespace Orthanc -{ - class FontRegistry : public boost::noncopyable - { - private: - typedef std::vector Fonts; - - Fonts fonts_; - - public: - ~FontRegistry(); - - void AddFromMemory(const std::string& font); - -#if ORTHANC_SANDBOXED == 0 - void AddFromFile(const std::string& path); -#endif - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 - void AddFromResource(EmbeddedResources::FileResourceId resource); -#endif - - size_t GetSize() const - { - return fonts_.size(); - } - - const Font& GetFont(size_t i) const; - - const Font* FindFont(const std::string& fontName) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "IImageWriter.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - -namespace Orthanc -{ -#if ORTHANC_SANDBOXED == 0 - void IImageWriter::WriteToFileInternal(const std::string& path, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - std::string compressed; - WriteToMemoryInternal(compressed, width, height, pitch, format, buffer); - SystemToolbox::WriteFile(compressed, path); - } -#endif -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/IImageWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,86 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ImageAccessor.h" - -#include - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -namespace Orthanc -{ - class IImageWriter : public boost::noncopyable - { - protected: - virtual void WriteToMemoryInternal(std::string& compressed, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) = 0; - -#if ORTHANC_SANDBOXED == 0 - virtual void WriteToFileInternal(const std::string& path, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); -#endif - - public: - virtual ~IImageWriter() - { - } - - virtual void WriteToMemory(std::string& compressed, - const ImageAccessor& accessor) - { - WriteToMemoryInternal(compressed, accessor.GetWidth(), accessor.GetHeight(), - accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); - } - -#if ORTHANC_SANDBOXED == 0 - virtual void WriteToFile(const std::string& path, - const ImageAccessor& accessor) - { - WriteToFileInternal(path, accessor.GetWidth(), accessor.GetHeight(), - accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer()); - } -#endif - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,307 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ImageAccessor.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../ChunkedBuffer.h" - -#include -#include -#include - - - -namespace Orthanc -{ - template - static void ToMatlabStringInternal(ChunkedBuffer& target, - const ImageAccessor& source) - { - target.AddChunk("double([ "); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - const PixelType* p = reinterpret_cast(source.GetConstRow(y)); - - std::string s; - if (y > 0) - { - s = "; "; - } - - s.reserve(source.GetWidth() * 8); - - for (unsigned int x = 0; x < source.GetWidth(); x++, p++) - { - s += boost::lexical_cast(static_cast(*p)) + " "; - } - - target.AddChunk(s); - } - - target.AddChunk("])"); - } - - - static void RGB24ToMatlabString(ChunkedBuffer& target, - const ImageAccessor& source) - { - assert(source.GetFormat() == PixelFormat_RGB24); - - target.AddChunk("double(permute(reshape([ "); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - - std::string s; - s.reserve(source.GetWidth() * 3 * 8); - - for (unsigned int x = 0; x < 3 * source.GetWidth(); x++, p++) - { - s += boost::lexical_cast(static_cast(*p)) + " "; - } - - target.AddChunk(s); - } - - target.AddChunk("], [ 3 " + boost::lexical_cast(source.GetHeight()) + - " " + boost::lexical_cast(source.GetWidth()) + " ]), [ 3 2 1 ]))"); - } - - - void* ImageAccessor::GetBuffer() const - { - if (readOnly_) - { - throw OrthancException(ErrorCode_ReadOnly, - "Trying to write to a read-only image"); - } - - return buffer_; - } - - - const void* ImageAccessor::GetConstRow(unsigned int y) const - { - if (buffer_ != NULL) - { - return buffer_ + y * pitch_; - } - else - { - return NULL; - } - } - - - void* ImageAccessor::GetRow(unsigned int y) const - { - if (readOnly_) - { - throw OrthancException(ErrorCode_ReadOnly, - "Trying to write to a read-only image"); - } - - if (buffer_ != NULL) - { - return buffer_ + y * pitch_; - } - else - { - return NULL; - } - } - - - void ImageAccessor::AssignEmpty(PixelFormat format) - { - readOnly_ = false; - format_ = format; - width_ = 0; - height_ = 0; - pitch_ = 0; - buffer_ = NULL; - } - - - void ImageAccessor::AssignReadOnly(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - const void *buffer) - { - readOnly_ = true; - format_ = format; - width_ = width; - height_ = height; - pitch_ = pitch; - buffer_ = reinterpret_cast(const_cast(buffer)); - - if (GetBytesPerPixel() * width_ > pitch_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - void ImageAccessor::AssignWritable(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - void *buffer) - { - readOnly_ = false; - format_ = format; - width_ = width; - height_ = height; - pitch_ = pitch; - buffer_ = reinterpret_cast(buffer); - - if (GetBytesPerPixel() * width_ > pitch_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - void ImageAccessor::GetWriteableAccessor(ImageAccessor& target) const - { - if (readOnly_) - { - throw OrthancException(ErrorCode_ReadOnly); - } - else - { - target.AssignWritable(format_, width_, height_, pitch_, buffer_); - } - } - - - void ImageAccessor::ToMatlabString(std::string& target) const - { - ChunkedBuffer buffer; - - switch (GetFormat()) - { - case PixelFormat_Grayscale8: - ToMatlabStringInternal(buffer, *this); - break; - - case PixelFormat_Grayscale16: - ToMatlabStringInternal(buffer, *this); - break; - - case PixelFormat_Grayscale32: - ToMatlabStringInternal(buffer, *this); - break; - - case PixelFormat_Grayscale64: - ToMatlabStringInternal(buffer, *this); - break; - - case PixelFormat_SignedGrayscale16: - ToMatlabStringInternal(buffer, *this); - break; - - case PixelFormat_Float32: - ToMatlabStringInternal(buffer, *this); - break; - - case PixelFormat_RGB24: - RGB24ToMatlabString(buffer, *this); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - buffer.Flatten(target); - } - - - - void ImageAccessor::GetRegion(ImageAccessor& accessor, - unsigned int x, - unsigned int y, - unsigned int width, - unsigned int height) const - { - if (x + width > width_ || - y + height > height_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (width == 0 || - height == 0) - { - accessor.AssignWritable(format_, 0, 0, 0, NULL); - } - else - { - uint8_t* p = (buffer_ + - y * pitch_ + - x * GetBytesPerPixel()); - - if (readOnly_) - { - accessor.AssignReadOnly(format_, width, height, pitch_, p); - } - else - { - accessor.AssignWritable(format_, width, height, pitch_, p); - } - } - } - - - void ImageAccessor::SetFormat(PixelFormat format) - { - if (readOnly_) - { - throw OrthancException(ErrorCode_ReadOnly, - "Trying to modify the format of a read-only image"); - } - - if (::Orthanc::GetBytesPerPixel(format) != ::Orthanc::GetBytesPerPixel(format_)) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat); - } - - format_ = format; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageAccessor.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include -#include -#include - -namespace Orthanc -{ - class ImageAccessor : public boost::noncopyable - { - private: - template - friend struct ImageTraits; - - bool readOnly_; - PixelFormat format_; - unsigned int width_; - unsigned int height_; - unsigned int pitch_; - uint8_t *buffer_; - - template - const T& GetPixelUnchecked(unsigned int x, - unsigned int y) const - { - const uint8_t* row = reinterpret_cast(buffer_) + y * pitch_; - return reinterpret_cast(row) [x]; - } - - - template - T& GetPixelUnchecked(unsigned int x, - unsigned int y) - { - uint8_t* row = reinterpret_cast(buffer_) + y * pitch_; - return reinterpret_cast(row) [x]; - } - - public: - ImageAccessor() - { - AssignEmpty(PixelFormat_Grayscale8); - } - - virtual ~ImageAccessor() - { - } - - bool IsReadOnly() const - { - return readOnly_; - } - - PixelFormat GetFormat() const - { - return format_; - } - - unsigned int GetBytesPerPixel() const - { - return ::Orthanc::GetBytesPerPixel(format_); - } - - unsigned int GetWidth() const - { - return width_; - } - - unsigned int GetHeight() const - { - return height_; - } - - unsigned int GetPitch() const - { - return pitch_; - } - - unsigned int GetSize() const - { - return GetHeight() * GetPitch(); - } - - const void* GetConstBuffer() const - { - return buffer_; - } - - void* GetBuffer() const; - - const void* GetConstRow(unsigned int y) const; - - void* GetRow(unsigned int y) const; - - void AssignEmpty(PixelFormat format); - - void AssignReadOnly(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - const void *buffer); - - void GetReadOnlyAccessor(ImageAccessor& target) const - { - target.AssignReadOnly(format_, width_, height_, pitch_, buffer_); - } - - void AssignWritable(PixelFormat format, - unsigned int width, - unsigned int height, - unsigned int pitch, - void *buffer); - - void GetWriteableAccessor(ImageAccessor& target) const; - - void ToMatlabString(std::string& target) const; - - void GetRegion(ImageAccessor& accessor, - unsigned int x, - unsigned int y, - unsigned int width, - unsigned int height) const; - - void SetFormat(PixelFormat format); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,180 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ImageBuffer.h" - -#include "../OrthancException.h" - -#include -#include - -namespace Orthanc -{ - void ImageBuffer::Allocate() - { - if (changed_) - { - Deallocate(); - - /* - if (forceMinimalPitch_) - { - TODO: Align pitch and memory buffer to optimal size for SIMD. - } - */ - - pitch_ = GetBytesPerPixel() * width_; - size_t size = pitch_ * height_; - - if (size == 0) - { - buffer_ = NULL; - } - else - { - buffer_ = malloc(size); - if (buffer_ == NULL) - { - throw OrthancException(ErrorCode_NotEnoughMemory, - "Failed to allocate an image buffer of size " + boost::lexical_cast(width_) + "x" + boost::lexical_cast(height_)); - } - } - - changed_ = false; - } - } - - - void ImageBuffer::Deallocate() - { - if (buffer_ != NULL) - { - free(buffer_); - buffer_ = NULL; - changed_ = true; - } - } - - - ImageBuffer::ImageBuffer(PixelFormat format, - unsigned int width, - unsigned int height, - bool forceMinimalPitch) : - forceMinimalPitch_(forceMinimalPitch) - { - Initialize(); - SetWidth(width); - SetHeight(height); - SetFormat(format); - } - - - void ImageBuffer::Initialize() - { - changed_ = false; - forceMinimalPitch_ = true; - format_ = PixelFormat_Grayscale8; - width_ = 0; - height_ = 0; - pitch_ = 0; - buffer_ = NULL; - } - - - void ImageBuffer::SetFormat(PixelFormat format) - { - if (format != format_) - { - changed_ = true; - format_ = format; - } - } - - - void ImageBuffer::SetWidth(unsigned int width) - { - if (width != width_) - { - changed_ = true; - width_ = width; - } - } - - - void ImageBuffer::SetHeight(unsigned int height) - { - if (height != height_) - { - changed_ = true; - height_ = height; - } - } - - - void ImageBuffer::GetReadOnlyAccessor(ImageAccessor& accessor) - { - Allocate(); - accessor.AssignReadOnly(format_, width_, height_, pitch_, buffer_); - } - - - void ImageBuffer::GetWriteableAccessor(ImageAccessor& accessor) - { - Allocate(); - accessor.AssignWritable(format_, width_, height_, pitch_, buffer_); - } - - - void ImageBuffer::AcquireOwnership(ImageBuffer& other) - { - // Remove the content of the current image - Deallocate(); - - // Force the allocation of the other image (if not already - // allocated) - other.Allocate(); - - // Transfer the content of the other image - changed_ = false; - forceMinimalPitch_ = other.forceMinimalPitch_; - format_ = other.format_; - width_ = other.width_; - height_ = other.height_; - pitch_ = other.pitch_; - buffer_ = other.buffer_; - - // Force the reinitialization of the other image - other.Initialize(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageBuffer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ImageAccessor.h" - -#include -#include -#include - -namespace Orthanc -{ - class ImageBuffer : public boost::noncopyable - { - private: - bool changed_; - - bool forceMinimalPitch_; // Currently unused - PixelFormat format_; - unsigned int width_; - unsigned int height_; - unsigned int pitch_; - void *buffer_; - - void Initialize(); - - void Allocate(); - - void Deallocate(); - - public: - ImageBuffer(PixelFormat format, - unsigned int width, - unsigned int height, - bool forceMinimalPitch); - - ImageBuffer() - { - Initialize(); - } - - ~ImageBuffer() - { - Deallocate(); - } - - PixelFormat GetFormat() const - { - return format_; - } - - void SetFormat(PixelFormat format); - - unsigned int GetWidth() const - { - return width_; - } - - void SetWidth(unsigned int width); - - unsigned int GetHeight() const - { - return height_; - } - - void SetHeight(unsigned int height); - - unsigned int GetBytesPerPixel() const - { - return ::Orthanc::GetBytesPerPixel(format_); - } - - void GetReadOnlyAccessor(ImageAccessor& accessor); - - void GetWriteableAccessor(ImageAccessor& accessor); - - bool IsMinimalPitchForced() const - { - return forceMinimalPitch_; - } - - void AcquireOwnership(ImageBuffer& other); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "Image.h" - -#include "../Compatibility.h" -#include "ImageProcessing.h" - -#include - -namespace Orthanc -{ - Image::Image(PixelFormat format, - unsigned int width, - unsigned int height, - bool forceMinimalPitch) : - image_(format, width, height, forceMinimalPitch) - { - ImageAccessor accessor; - image_.GetWriteableAccessor(accessor); - - AssignWritable(format, width, height, accessor.GetPitch(), accessor.GetBuffer()); - } - - - Image* Image::Clone(const ImageAccessor& source) - { - std::unique_ptr target(new Image(source.GetFormat(), source.GetWidth(), source.GetHeight(), false)); - ImageProcessing::Copy(*target, source); - return target.release(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/Image.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,54 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ImageAccessor.h" -#include "ImageBuffer.h" - -namespace Orthanc -{ - class Image : public ImageAccessor - { - private: - ImageBuffer image_; - - public: - Image(PixelFormat format, - unsigned int width, - unsigned int height, - bool forceMinimalPitch); - - static Image* Clone(const ImageAccessor& source); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2466 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "ImageProcessing.h" - -#include "Image.h" -#include "ImageTraits.h" -#include "PixelTraits.h" -#include "../OrthancException.h" - -#ifdef __EMSCRIPTEN__ -/* - Avoid this error: - ----------------- - .../boost/math/special_functions/round.hpp:118:12: warning: implicit conversion from 'std::__2::numeric_limits::type' (aka 'long long') to 'float' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-int-float-conversion] - .../mnt/c/osi/dev/orthanc/Core/Images/ImageProcessing.cpp:333:28: note: in instantiation of function template specialization 'boost::math::llround' requested here - .../mnt/c/osi/dev/orthanc/Core/Images/ImageProcessing.cpp:1006:9: note: in instantiation of function template specialization 'Orthanc::MultiplyConstantInternal' requested here -*/ -#pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" -#endif - -#include - -#include -#include -#include -#include -#include - -namespace Orthanc -{ - double ImageProcessing::ImagePoint::GetDistanceTo(const ImagePoint& other) const - { - double dx = (double)(other.GetX() - GetX()); - double dy = (double)(other.GetY() - GetY()); - return sqrt(dx * dx + dy * dy); - } - - double ImageProcessing::ImagePoint::GetDistanceToLine(double a, double b, double c) const // where ax + by + c = 0 is the equation of the line - { - return std::abs(a * static_cast(GetX()) + b * static_cast(GetY()) + c) / pow(a * a + b * b, 0.5); - } - - template - static void ConvertInternal(ImageAccessor& target, - const ImageAccessor& source) - { - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - assert(sizeof(TargetType) <= 2); // Safeguard to remember about "float/double" - const TargetType minValue = std::numeric_limits::min(); - const TargetType maxValue = std::numeric_limits::max(); - - const unsigned int width = source.GetWidth(); - const unsigned int height = source.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - TargetType* t = reinterpret_cast(target.GetRow(y)); - const SourceType* s = reinterpret_cast(source.GetConstRow(y)); - - for (unsigned int x = 0; x < width; x++, t++, s++) - { - if (static_cast(*s) < static_cast(minValue)) - { - *t = minValue; - } - else if (static_cast(*s) > static_cast(maxValue)) - { - *t = maxValue; - } - else - { - *t = static_cast(*s); - } - } - } - } - - - template - static void ConvertGrayscaleToFloat(ImageAccessor& target, - const ImageAccessor& source) - { - assert(sizeof(float) == 4); - - const unsigned int width = source.GetWidth(); - const unsigned int height = source.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - float* t = reinterpret_cast(target.GetRow(y)); - const SourceType* s = reinterpret_cast(source.GetConstRow(y)); - - for (unsigned int x = 0; x < width; x++, t++, s++) - { - *t = static_cast(*s); - } - } - } - - - template - static void ConvertFloatToGrayscale(ImageAccessor& target, - const ImageAccessor& source) - { - typedef typename PixelTraits::PixelType TargetType; - - assert(sizeof(float) == 4); - - const unsigned int width = source.GetWidth(); - const unsigned int height = source.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - TargetType* q = reinterpret_cast(target.GetRow(y)); - const float* p = reinterpret_cast(source.GetConstRow(y)); - - for (unsigned int x = 0; x < width; x++, p++, q++) - { - PixelTraits::FloatToPixel(*q, *p); - } - } - } - - - template - static void ConvertColorToGrayscale(ImageAccessor& target, - const ImageAccessor& source) - { - assert(source.GetFormat() == PixelFormat_RGB24); - - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - assert(sizeof(TargetType) <= 2); // Safeguard to remember about "float/double" - const TargetType minValue = std::numeric_limits::min(); - const TargetType maxValue = std::numeric_limits::max(); - - const unsigned int width = source.GetWidth(); - const unsigned int height = source.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - TargetType* t = reinterpret_cast(target.GetRow(y)); - const uint8_t* s = reinterpret_cast(source.GetConstRow(y)); - - for (unsigned int x = 0; x < width; x++, t++, s += 3) - { - // Y = 0.2126 R + 0.7152 G + 0.0722 B - int32_t v = (2126 * static_cast(s[0]) + - 7152 * static_cast(s[1]) + - 0722 * static_cast(s[2])) / 10000; - - if (static_cast(v) < static_cast(minValue)) - { - *t = minValue; - } - else if (static_cast(v) > static_cast(maxValue)) - { - *t = maxValue; - } - else - { - *t = static_cast(v); - } - } - } - } - - - static void MemsetZeroInternal(ImageAccessor& image) - { - const unsigned int height = image.GetHeight(); - const size_t lineSize = image.GetBytesPerPixel() * image.GetWidth(); - const size_t pitch = image.GetPitch(); - - uint8_t *p = reinterpret_cast(image.GetBuffer()); - - for (unsigned int y = 0; y < height; y++) - { - memset(p, 0, lineSize); - p += pitch; - } - } - - - template - static void SetInternal(ImageAccessor& image, - int64_t constant) - { - if (constant == 0 && - (image.GetFormat() == PixelFormat_Grayscale8 || - image.GetFormat() == PixelFormat_Grayscale16 || - image.GetFormat() == PixelFormat_Grayscale32 || - image.GetFormat() == PixelFormat_Grayscale64 || - image.GetFormat() == PixelFormat_SignedGrayscale16)) - { - MemsetZeroInternal(image); - } - else - { - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - PixelType* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - *p = static_cast(constant); - } - } - } - } - - - template - static void GetMinMaxValueInternal(PixelType& minValue, - PixelType& maxValue, - const ImageAccessor& source, - const PixelType LowestValue = std::numeric_limits::min()) - { - // Deal with the special case of empty image - if (source.GetWidth() == 0 || - source.GetHeight() == 0) - { - minValue = 0; - maxValue = 0; - return; - } - - minValue = std::numeric_limits::max(); - maxValue = LowestValue; - - const unsigned int height = source.GetHeight(); - const unsigned int width = source.GetWidth(); - - for (unsigned int y = 0; y < height; y++) - { - const PixelType* p = reinterpret_cast(source.GetConstRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - if (*p < minValue) - { - minValue = *p; - } - - if (*p > maxValue) - { - maxValue = *p; - } - } - } - } - - - - template - static void AddConstantInternal(ImageAccessor& image, - int64_t constant) - { - if (constant == 0) - { - return; - } - - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - assert(sizeof(PixelType) <= 2); // Safeguard to remember about "float/double" - const int64_t minValue = std::numeric_limits::min(); - const int64_t maxValue = std::numeric_limits::max(); - - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - PixelType* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - int64_t v = static_cast(*p) + constant; - - if (v > maxValue) - { - *p = std::numeric_limits::max(); - } - else if (v < minValue) - { - *p = std::numeric_limits::min(); - } - else - { - *p = static_cast(v); - } - } - } - } - - - - template - static void MultiplyConstantInternal(ImageAccessor& image, - float factor) - { - if (std::abs(factor - 1.0f) <= std::numeric_limits::epsilon()) - { - return; - } - - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - assert(sizeof(PixelType) <= 2); // Safeguard to remember about "float/double" - const int64_t minValue = std::numeric_limits::min(); - const int64_t maxValue = std::numeric_limits::max(); - - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - PixelType* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - int64_t v; - if (UseRound) - { - // The "round" operation is very costly - v = boost::math::llround(static_cast(*p) * factor); - } - else - { - v = static_cast(static_cast(*p) * factor); - } - - if (v > maxValue) - { - *p = std::numeric_limits::max(); - } - else if (v < minValue) - { - *p = std::numeric_limits::min(); - } - else - { - *p = static_cast(v); - } - } - } - } - - - // Computes "a * x + b" at each pixel => Note that this is not the - // same convention as in "ShiftScale()" - template - static void ShiftScaleInternal(ImageAccessor& target, - const ImageAccessor& source, - float a, - float b, - const TargetType LowestValue) - // This function can be applied inplace (source == target) - { - if (source.GetWidth() != target.GetWidth() || - source.GetHeight() != target.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - if (&source == &target && - source.GetFormat() != target.GetFormat()) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat); - } - - const TargetType minPixelValue = LowestValue; - const TargetType maxPixelValue = std::numeric_limits::max(); - const float minFloatValue = static_cast(LowestValue); - const float maxFloatValue = static_cast(maxPixelValue); - - const unsigned int height = target.GetHeight(); - const unsigned int width = target.GetWidth(); - - for (unsigned int y = 0; y < height; y++) - { - TargetType* p = reinterpret_cast(target.GetRow(y)); - const SourceType* q = reinterpret_cast(source.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++, q++) - { - float v = a * static_cast(*q) + b; - - if (v >= maxFloatValue) - { - *p = maxPixelValue; - } - else if (v <= minFloatValue) - { - *p = minPixelValue; - } - else if (UseRound) - { - // The "round" operation is very costly - *p = static_cast(boost::math::iround(v)); - } - else - { - *p = static_cast(std::floor(v)); - } - - if (Invert) - { - *p = maxPixelValue - *p; - } - } - } - } - - template - static void ShiftRightInternal(ImageAccessor& image, - unsigned int shift) - { - const unsigned int height = image.GetHeight(); - const unsigned int width = image.GetWidth(); - - for (unsigned int y = 0; y < height; y++) - { - PixelType* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - *p = *p >> shift; - } - } - } - - template - static void ShiftLeftInternal(ImageAccessor& image, - unsigned int shift) - { - const unsigned int height = image.GetHeight(); - const unsigned int width = image.GetWidth(); - - for (unsigned int y = 0; y < height; y++) - { - PixelType* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - *p = *p << shift; - } - } - } - - void ImageProcessing::Copy(ImageAccessor& target, - const ImageAccessor& source) - { - if (target.GetWidth() != source.GetWidth() || - target.GetHeight() != source.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - if (target.GetFormat() != source.GetFormat()) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat); - } - - unsigned int lineSize = source.GetBytesPerPixel() * source.GetWidth(); - - assert(source.GetPitch() >= lineSize && target.GetPitch() >= lineSize); - - for (unsigned int y = 0; y < source.GetHeight(); y++) - { - memcpy(target.GetRow(y), source.GetConstRow(y), lineSize); - } - } - - template - static void ApplyWindowingInternal(ImageAccessor& target, - const ImageAccessor& source, - float windowCenter, - float windowWidth, - float rescaleSlope, - float rescaleIntercept, - bool invert) - { - assert(sizeof(SourceType) == source.GetBytesPerPixel() && - sizeof(TargetType) == target.GetBytesPerPixel()); - - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - assert(sizeof(TargetType) <= 2); // Safeguard to remember about "float/double" - const TargetType minTargetValue = std::numeric_limits::min(); - const TargetType maxTargetValue = std::numeric_limits::max(); - const float maxFloatValue = static_cast(maxTargetValue); - - const float windowIntercept = windowCenter - windowWidth / 2.0f; - const float windowSlope = (maxFloatValue + 1.0f) / windowWidth; - - const float a = rescaleSlope * windowSlope; - const float b = (rescaleIntercept - windowIntercept) * windowSlope; - - if (invert) - { - ShiftScaleInternal(target, source, a, b, minTargetValue); - } - else - { - ShiftScaleInternal(target, source, a, b, minTargetValue); - } - } - - void ImageProcessing::ApplyWindowing_Deprecated(ImageAccessor& target, - const ImageAccessor& source, - float windowCenter, - float windowWidth, - float rescaleSlope, - float rescaleIntercept, - bool invert) - { - if (target.GetWidth() != source.GetWidth() || - target.GetHeight() != source.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - switch (source.GetFormat()) - { - case Orthanc::PixelFormat_Float32: - { - switch (target.GetFormat()) - { - case Orthanc::PixelFormat_Grayscale8: - ApplyWindowingInternal(target, source, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); - break; - case Orthanc::PixelFormat_Grayscale16: - ApplyWindowingInternal(target, source, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); - break; - default: - throw OrthancException(ErrorCode_NotImplemented); - } - };break; - case Orthanc::PixelFormat_Grayscale8: - { - switch (target.GetFormat()) - { - case Orthanc::PixelFormat_Grayscale8: - ApplyWindowingInternal(target, source, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); - break; - case Orthanc::PixelFormat_Grayscale16: - ApplyWindowingInternal(target, source, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); - break; - default: - throw OrthancException(ErrorCode_NotImplemented); - } - };break; - case Orthanc::PixelFormat_Grayscale16: - { - switch (target.GetFormat()) - { - case Orthanc::PixelFormat_Grayscale8: - ApplyWindowingInternal(target, source, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); - break; - case Orthanc::PixelFormat_Grayscale16: - ApplyWindowingInternal(target, source, windowCenter, windowWidth, rescaleSlope, rescaleIntercept, invert); - break; - default: - throw OrthancException(ErrorCode_NotImplemented); - } - };break; - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::Convert(ImageAccessor& target, - const ImageAccessor& source) - { - if (target.GetWidth() != source.GetWidth() || - target.GetHeight() != source.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - const unsigned int width = source.GetWidth(); - const unsigned int height = source.GetHeight(); - - if (source.GetFormat() == target.GetFormat()) - { - Copy(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_Grayscale8) - { - ConvertInternal(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_SignedGrayscale16 && - source.GetFormat() == PixelFormat_Grayscale8) - { - ConvertInternal(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_Grayscale16) - { - ConvertInternal(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_SignedGrayscale16 && - source.GetFormat() == PixelFormat_Grayscale16) - { - ConvertInternal(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_SignedGrayscale16) - { - ConvertInternal(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_SignedGrayscale16) - { - ConvertInternal(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_RGB24) - { - ConvertColorToGrayscale(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_RGB24) - { - ConvertColorToGrayscale(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_SignedGrayscale16 && - source.GetFormat() == PixelFormat_RGB24) - { - ConvertColorToGrayscale(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Float32 && - source.GetFormat() == PixelFormat_Grayscale8) - { - ConvertGrayscaleToFloat(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Float32 && - source.GetFormat() == PixelFormat_Grayscale16) - { - ConvertGrayscaleToFloat(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Float32 && - source.GetFormat() == PixelFormat_Grayscale32) - { - ConvertGrayscaleToFloat(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Float32 && - source.GetFormat() == PixelFormat_SignedGrayscale16) - { - ConvertGrayscaleToFloat(target, source); - return; - } - - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_RGBA32) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++, q++) - { - *q = static_cast((2126 * static_cast(p[0]) + - 7152 * static_cast(p[1]) + - 0722 * static_cast(p[2])) / 10000); - p += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_BGRA32) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++, q++) - { - *q = static_cast((2126 * static_cast(p[2]) + - 7152 * static_cast(p[1]) + - 0722 * static_cast(p[0])) / 10000); - p += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_RGB24 && - source.GetFormat() == PixelFormat_RGBA32) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = p[0]; - q[1] = p[1]; - q[2] = p[2]; - p += 4; - q += 3; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_RGB24 && - source.GetFormat() == PixelFormat_BGRA32) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = p[2]; - q[1] = p[1]; - q[2] = p[0]; - p += 4; - q += 3; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_RGBA32 && - source.GetFormat() == PixelFormat_RGB24) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = p[0]; - q[1] = p[1]; - q[2] = p[2]; - q[3] = 255; // Set the alpha channel to full opacity - p += 3; - q += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_RGB24 && - source.GetFormat() == PixelFormat_Grayscale8) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = *p; - q[1] = *p; - q[2] = *p; - p += 1; - q += 3; - } - } - - return; - } - - if ((target.GetFormat() == PixelFormat_RGBA32 || - target.GetFormat() == PixelFormat_BGRA32) && - source.GetFormat() == PixelFormat_Grayscale8) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = *p; - q[1] = *p; - q[2] = *p; - q[3] = 255; - p += 1; - q += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_BGRA32 && - source.GetFormat() == PixelFormat_Grayscale16) - { - for (unsigned int y = 0; y < height; y++) - { - const uint16_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - uint8_t value = (*p < 256 ? *p : 255); - q[0] = value; - q[1] = value; - q[2] = value; - q[3] = 255; - p += 1; - q += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_BGRA32 && - source.GetFormat() == PixelFormat_SignedGrayscale16) - { - for (unsigned int y = 0; y < height; y++) - { - const int16_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - uint8_t value; - if (*p < 0) - { - value = 0; - } - else if (*p > 255) - { - value = 255; - } - else - { - value = static_cast(*p); - } - - q[0] = value; - q[1] = value; - q[2] = value; - q[3] = 255; - p += 1; - q += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_BGRA32 && - source.GetFormat() == PixelFormat_RGB24) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = p[2]; - q[1] = p[1]; - q[2] = p[0]; - q[3] = 255; - p += 3; - q += 4; - } - } - - return; - } - - if ((target.GetFormat() == PixelFormat_BGRA32 && - source.GetFormat() == PixelFormat_RGBA32) - || (target.GetFormat() == PixelFormat_RGBA32 && - source.GetFormat() == PixelFormat_BGRA32)) - { - for (unsigned int y = 0; y < height; y++) - { - const uint8_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = p[2]; - q[1] = p[1]; - q[2] = p[0]; - q[3] = p[3]; - p += 4; - q += 4; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_RGB24 && - source.GetFormat() == PixelFormat_RGB48) - { - for (unsigned int y = 0; y < height; y++) - { - const uint16_t* p = reinterpret_cast(source.GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - for (unsigned int x = 0; x < width; x++) - { - q[0] = p[0] >> 8; - q[1] = p[1] >> 8; - q[2] = p[2] >> 8; - p += 3; - q += 3; - } - } - - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale16 && - source.GetFormat() == PixelFormat_Float32) - { - ConvertFloatToGrayscale(target, source); - return; - } - - if (target.GetFormat() == PixelFormat_Grayscale8 && - source.GetFormat() == PixelFormat_Float32) - { - ConvertFloatToGrayscale(target, source); - return; - } - - throw OrthancException(ErrorCode_NotImplemented); - } - - - - void ImageProcessing::Set(ImageAccessor& image, - int64_t value) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - SetInternal(image, value); - return; - - case PixelFormat_Grayscale16: - SetInternal(image, value); - return; - - case PixelFormat_Grayscale32: - SetInternal(image, value); - return; - - case PixelFormat_Grayscale64: - SetInternal(image, value); - return; - - case PixelFormat_SignedGrayscale16: - SetInternal(image, value); - return; - - case PixelFormat_Float32: - assert(sizeof(float) == 4); - SetInternal(image, value); - return; - - case PixelFormat_RGBA32: - case PixelFormat_BGRA32: - case PixelFormat_RGB24: - { - uint8_t v = static_cast(value); - Set(image, v, v, v, v); // Use the color version - return; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::Set(ImageAccessor& image, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha) - { - uint8_t p[4]; - unsigned int size; - - switch (image.GetFormat()) - { - case PixelFormat_RGBA32: - p[0] = red; - p[1] = green; - p[2] = blue; - p[3] = alpha; - size = 4; - break; - - case PixelFormat_BGRA32: - p[0] = blue; - p[1] = green; - p[2] = red; - p[3] = alpha; - size = 4; - break; - - case PixelFormat_RGB24: - p[0] = red; - p[1] = green; - p[2] = blue; - size = 3; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - uint8_t* q = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++) - { - for (unsigned int i = 0; i < size; i++) - { - q[i] = p[i]; - } - - q += size; - } - } - } - - void ImageProcessing::Set(ImageAccessor& image, - uint8_t red, - uint8_t green, - uint8_t blue, - ImageAccessor& alpha) - { - uint8_t p[4]; - - if (alpha.GetWidth() != image.GetWidth() || alpha.GetHeight() != image.GetHeight()) - { - throw OrthancException(ErrorCode_IncompatibleImageSize); - } - - if (alpha.GetFormat() != PixelFormat_Grayscale8) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - switch (image.GetFormat()) - { - case PixelFormat_RGBA32: - p[0] = red; - p[1] = green; - p[2] = blue; - break; - - case PixelFormat_BGRA32: - p[0] = blue; - p[1] = green; - p[2] = red; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - uint8_t* q = reinterpret_cast(image.GetRow(y)); - uint8_t* a = reinterpret_cast(alpha.GetRow(y)); - - for (unsigned int x = 0; x < width; x++) - { - for (unsigned int i = 0; i < 3; i++) - { - q[i] = p[i]; - } - q[3] = *a; - q += 4; - ++a; - } - } - } - - - void ImageProcessing::ShiftRight(ImageAccessor& image, - unsigned int shift) - { - if (image.GetWidth() == 0 || - image.GetHeight() == 0 || - shift == 0) - { - // Nothing to do - return; - } - - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - { - ShiftRightInternal(image, shift); - break; - } - - case PixelFormat_Grayscale16: - { - ShiftRightInternal(image, shift); - break; - } - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - void ImageProcessing::ShiftLeft(ImageAccessor& image, - unsigned int shift) - { - if (image.GetWidth() == 0 || - image.GetHeight() == 0 || - shift == 0) - { - // Nothing to do - return; - } - - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - { - ShiftLeftInternal(image, shift); - break; - } - - case PixelFormat_Grayscale16: - { - ShiftLeftInternal(image, shift); - break; - } - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - void ImageProcessing::GetMinMaxIntegerValue(int64_t& minValue, - int64_t& maxValue, - const ImageAccessor& image) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - { - uint8_t a, b; - GetMinMaxValueInternal(a, b, image); - minValue = a; - maxValue = b; - break; - } - - case PixelFormat_Grayscale16: - { - uint16_t a, b; - GetMinMaxValueInternal(a, b, image); - minValue = a; - maxValue = b; - break; - } - - case PixelFormat_Grayscale32: - { - uint32_t a, b; - GetMinMaxValueInternal(a, b, image); - minValue = a; - maxValue = b; - break; - } - - case PixelFormat_SignedGrayscale16: - { - int16_t a, b; - GetMinMaxValueInternal(a, b, image); - minValue = a; - maxValue = b; - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::GetMinMaxFloatValue(float& minValue, - float& maxValue, - const ImageAccessor& image) - { - switch (image.GetFormat()) - { - case PixelFormat_Float32: - { - assert(sizeof(float) == 4); - float a, b; - - /** - * WARNING - On floating-point types, the minimal value is - * "-FLT_MAX" (as implemented by "::lowest()"), not "FLT_MIN" - * (as implemented by "::min()") - * https://en.cppreference.com/w/cpp/types/numeric_limits - **/ - GetMinMaxValueInternal(a, b, image, -std::numeric_limits::max()); - minValue = a; - maxValue = b; - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - - void ImageProcessing::AddConstant(ImageAccessor& image, - int64_t value) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - AddConstantInternal(image, value); - return; - - case PixelFormat_Grayscale16: - AddConstantInternal(image, value); - return; - - case PixelFormat_SignedGrayscale16: - AddConstantInternal(image, value); - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::MultiplyConstant(ImageAccessor& image, - float factor, - bool useRound) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - if (useRound) - { - MultiplyConstantInternal(image, factor); - } - else - { - MultiplyConstantInternal(image, factor); - } - return; - - case PixelFormat_Grayscale16: - if (useRound) - { - MultiplyConstantInternal(image, factor); - } - else - { - MultiplyConstantInternal(image, factor); - } - return; - - case PixelFormat_SignedGrayscale16: - if (useRound) - { - MultiplyConstantInternal(image, factor); - } - else - { - MultiplyConstantInternal(image, factor); - } - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::ShiftScale(ImageAccessor& image, - float offset, - float scaling, - bool useRound) - { - // Rewrite "(x + offset) * scaling" as "a * x + b" - - const float a = scaling; - const float b = offset * scaling; - - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - if (useRound) - { - ShiftScaleInternal(image, image, a, b, std::numeric_limits::min()); - } - else - { - ShiftScaleInternal(image, image, a, b, std::numeric_limits::min()); - } - return; - - case PixelFormat_Grayscale16: - if (useRound) - { - ShiftScaleInternal(image, image, a, b, std::numeric_limits::min()); - } - else - { - ShiftScaleInternal(image, image, a, b, std::numeric_limits::min()); - } - return; - - case PixelFormat_SignedGrayscale16: - if (useRound) - { - ShiftScaleInternal(image, image, a, b, std::numeric_limits::min()); - } - else - { - ShiftScaleInternal(image, image, a, b, std::numeric_limits::min()); - } - return; - - case PixelFormat_Float32: - // "::min()" must be replaced by "::lowest()" or "-::max()" if dealing with float or double. - if (useRound) - { - ShiftScaleInternal(image, image, a, b, -std::numeric_limits::max()); - } - else - { - ShiftScaleInternal(image, image, a, b, -std::numeric_limits::max()); - } - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::ShiftScale(ImageAccessor& target, - const ImageAccessor& source, - float offset, - float scaling, - bool useRound) - { - // Rewrite "(x + offset) * scaling" as "a * x + b" - - const float a = scaling; - const float b = offset * scaling; - - switch (target.GetFormat()) - { - case PixelFormat_Grayscale8: - - switch (source.GetFormat()) - { - case PixelFormat_Float32: - if (useRound) - { - ShiftScaleInternal( - target, source, a, b, std::numeric_limits::min()); - } - else - { - ShiftScaleInternal( - target, source, a, b, std::numeric_limits::min()); - } - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::Invert(ImageAccessor& image, int64_t maxValue) - { - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - switch (image.GetFormat()) - { - case PixelFormat_Grayscale16: - { - uint16_t maxValueUint16 = (uint16_t)(std::min(maxValue, static_cast(std::numeric_limits::max()))); - - for (unsigned int y = 0; y < height; y++) - { - uint16_t* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - *p = maxValueUint16 - (*p); - } - } - - return; - } - case PixelFormat_Grayscale8: - { - uint8_t maxValueUint8 = (uint8_t)(std::min(maxValue, static_cast(std::numeric_limits::max()))); - - for (unsigned int y = 0; y < height; y++) - { - uint8_t* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++) - { - *p = maxValueUint8 - (*p); - } - } - - return; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - - } - - void ImageProcessing::Invert(ImageAccessor& image) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - return Invert(image, 255); - default: - throw OrthancException(ErrorCode_NotImplemented); // you should use the Invert(image, maxValue) overload - } - } - - - - namespace - { - template - class BresenhamPixelWriter - { - private: - typedef typename PixelTraits::PixelType PixelType; - - Orthanc::ImageAccessor& image_; - PixelType value_; - - void PlotLineLow(int x0, - int y0, - int x1, - int y1) - { - int dx = x1 - x0; - int dy = y1 - y0; - int yi = 1; - - if (dy < 0) - { - yi = -1; - dy = -dy; - } - - int d = 2 * dy - dx; - int y = y0; - - for (int x = x0; x <= x1; x++) - { - Write(x, y); - - if (d > 0) - { - y = y + yi; - d = d - 2 * dx; - } - - d = d + 2*dy; - } - } - - void PlotLineHigh(int x0, - int y0, - int x1, - int y1) - { - int dx = x1 - x0; - int dy = y1 - y0; - int xi = 1; - - if (dx < 0) - { - xi = -1; - dx = -dx; - } - - int d = 2 * dx - dy; - int x = x0; - - for (int y = y0; y <= y1; y++) - { - Write(x, y); - - if (d > 0) - { - x = x + xi; - d = d - 2 * dy; - } - - d = d + 2 * dx; - } - } - - public: - BresenhamPixelWriter(Orthanc::ImageAccessor& image, - int64_t value) : - image_(image), - value_(PixelTraits::IntegerToPixel(value)) - { - } - - BresenhamPixelWriter(Orthanc::ImageAccessor& image, - const PixelType& value) : - image_(image), - value_(value) - { - } - - void Write(int x, - int y) - { - if (x >= 0 && - y >= 0 && - static_cast(x) < image_.GetWidth() && - static_cast(y) < image_.GetHeight()) - { - PixelType* p = reinterpret_cast(image_.GetRow(y)); - p[x] = value_; - } - } - - void DrawSegment(int x0, - int y0, - int x1, - int y1) - { - // This is an implementation of Bresenham's line algorithm - // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm#All_cases - - if (abs(y1 - y0) < abs(x1 - x0)) - { - if (x0 > x1) - { - PlotLineLow(x1, y1, x0, y0); - } - else - { - PlotLineLow(x0, y0, x1, y1); - } - } - else - { - if (y0 > y1) - { - PlotLineHigh(x1, y1, x0, y0); - } - else - { - PlotLineHigh(x0, y0, x1, y1); - } - } - } - }; - } - - - void ImageProcessing::DrawLineSegment(ImageAccessor& image, - int x0, - int y0, - int x1, - int y1, - int64_t value) - { - switch (image.GetFormat()) - { - case Orthanc::PixelFormat_Grayscale8: - { - BresenhamPixelWriter writer(image, value); - writer.DrawSegment(x0, y0, x1, y1); - break; - } - - case Orthanc::PixelFormat_Grayscale16: - { - BresenhamPixelWriter writer(image, value); - writer.DrawSegment(x0, y0, x1, y1); - break; - } - - case Orthanc::PixelFormat_SignedGrayscale16: - { - BresenhamPixelWriter writer(image, value); - writer.DrawSegment(x0, y0, x1, y1); - break; - } - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::DrawLineSegment(ImageAccessor& image, - int x0, - int y0, - int x1, - int y1, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha) - { - switch (image.GetFormat()) - { - case Orthanc::PixelFormat_BGRA32: - { - PixelTraits::PixelType pixel; - pixel.red_ = red; - pixel.green_ = green; - pixel.blue_ = blue; - pixel.alpha_ = alpha; - - BresenhamPixelWriter writer(image, pixel); - writer.DrawSegment(x0, y0, x1, y1); - break; - } - - case Orthanc::PixelFormat_RGBA32: - { - PixelTraits::PixelType pixel; - pixel.red_ = red; - pixel.green_ = green; - pixel.blue_ = blue; - pixel.alpha_ = alpha; - - BresenhamPixelWriter writer(image, pixel); - writer.DrawSegment(x0, y0, x1, y1); - break; - } - - case Orthanc::PixelFormat_RGB24: - { - PixelTraits::PixelType pixel; - pixel.red_ = red; - pixel.green_ = green; - pixel.blue_ = blue; - - BresenhamPixelWriter writer(image, pixel); - writer.DrawSegment(x0, y0, x1, y1); - break; - } - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - } - - void ComputePolygonExtent(int32_t& left, int32_t& right, int32_t& top, int32_t& bottom, const std::vector& points) - { - left = std::numeric_limits::max(); - right = std::numeric_limits::min(); - top = std::numeric_limits::max(); - bottom = std::numeric_limits::min(); - - for (size_t i = 0; i < points.size(); i++) - { - const ImageProcessing::ImagePoint& p = points[i]; - left = std::min(p.GetX(), left); - right = std::max(p.GetX(), right); - bottom = std::max(p.GetY(), bottom); - top = std::min(p.GetY(), top); - } - } - - template - void FillPolygon_(ImageAccessor& image, - const std::vector& points, - int64_t value_) - { - typedef typename PixelTraits::PixelType TargetType; - - TargetType value = PixelTraits::IntegerToPixel(value_); - int imageWidth = static_cast(image.GetWidth()); - int imageHeight = static_cast(image.GetHeight()); - int32_t left; - int32_t right; - int32_t top; - int32_t bottom; - - // TODO: test clipping in UT (in Trello board) - ComputePolygonExtent(left, right, top, bottom, points); - - // clip the computed extent with the target image - // L and R - left = std::max(0, left); - left = std::min(imageWidth, left); - right = std::max(0, right); - right = std::min(imageWidth, right); - if (left > right) - std::swap(left, right); - - // T and B - top = std::max(0, top); - top = std::min(imageHeight, top); - bottom = std::max(0, bottom); - bottom = std::min(imageHeight, bottom); - if (top > bottom) - std::swap(top, bottom); - - // from http://alienryderflex.com/polygon_fill/ - - // convert all "corner" points to double only once - std::vector cpx; - std::vector cpy; - size_t cpSize = points.size(); - for (size_t i = 0; i < points.size(); i++) - { - if (points[i].GetX() < 0 || points[i].GetX() >= imageWidth - || points[i].GetY() < 0 || points[i].GetY() >= imageHeight) - { - throw Orthanc::OrthancException(ErrorCode_ParameterOutOfRange); - } - cpx.push_back((double)points[i].GetX()); - cpy.push_back((double)points[i].GetY()); - } - - // Draw the lines segments - for (size_t i = 0; i < (points.size() -1); i++) - { - ImageProcessing::DrawLineSegment(image, points[i].GetX(), points[i].GetY(), points[i+1].GetX(), points[i+1].GetY(), value_); - } - ImageProcessing::DrawLineSegment(image, points[points.size() -1].GetX(), points[points.size() -1].GetY(), points[0].GetX(), points[0].GetY(), value_); - - std::vector nodeX; - nodeX.resize(cpSize); - int nodes, pixelX, pixelY, i, j, swap ; - - // Loop through the rows of the image. - for (pixelY = top; pixelY < bottom; pixelY++) - { - double y = (double)pixelY; - // Build a list of nodes. - nodes = 0; - j = static_cast(cpSize) - 1; - - for (i = 0; i < static_cast(cpSize); i++) - { - if ((cpy[i] < y && cpy[j] >= y) || (cpy[j] < y && cpy[i] >= y)) - { - nodeX[nodes++] = (int32_t)(cpx[i] + (y - cpy[i])/(cpy[j] - cpy[i]) * (cpx[j] - cpx[i])); - } - j=i; - } - - // Sort the nodes, via a simple “Bubble†sort. - i=0; - while (i < nodes-1) - { - if (nodeX[i] > nodeX[i+1]) - { - swap = nodeX[i]; - nodeX[i] = nodeX[i+1]; - nodeX[i+1] = swap; - if (i > 0) - { - i--; - } - } - else - { - i++; - } - } - - TargetType* row = reinterpret_cast(image.GetRow(pixelY)); - // Fill the pixels between node pairs. - for (i = 0; i < nodes; i += 2) - { - if (nodeX[i] >= right) - break; - - if (nodeX[i + 1] >= left) - { - if (nodeX[i] < left) - { - nodeX[i] = left; - } - - if (nodeX[i + 1] > right) - { - nodeX[i + 1] = right; - } - - for (pixelX = nodeX[i]; pixelX <= nodeX[i + 1]; pixelX++) - { - *(row + pixelX) = value; - } - } - } - } - } - - void ImageProcessing::FillPolygon(ImageAccessor& image, - const std::vector& points, - int64_t value) - { - switch (image.GetFormat()) - { - case Orthanc::PixelFormat_Grayscale8: - { - FillPolygon_(image, points, value); - break; - } - case Orthanc::PixelFormat_Grayscale16: - { - FillPolygon_(image, points, value); - break; - } - case Orthanc::PixelFormat_SignedGrayscale16: - { - FillPolygon_(image, points, value); - break; - } - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - } - - - template - static void ResizeInternal(ImageAccessor& target, - const ImageAccessor& source) - { - assert(target.GetFormat() == source.GetFormat() && - target.GetFormat() == Format); - - const unsigned int sourceWidth = source.GetWidth(); - const unsigned int sourceHeight = source.GetHeight(); - const unsigned int targetWidth = target.GetWidth(); - const unsigned int targetHeight = target.GetHeight(); - - if (targetWidth == 0 || targetHeight == 0) - { - return; - } - - if (sourceWidth == 0 || sourceHeight == 0) - { - // Avoids division by zero below - ImageProcessing::Set(target, 0); - return; - } - - const float scaleX = static_cast(sourceWidth) / static_cast(targetWidth); - const float scaleY = static_cast(sourceHeight) / static_cast(targetHeight); - - - /** - * Create two lookup tables to quickly know the (x,y) position - * in the source image, given the (x,y) position in the target - * image. - **/ - - std::vector lookupX(targetWidth); - - for (unsigned int x = 0; x < targetWidth; x++) - { - int sourceX = static_cast(std::floor((static_cast(x) + 0.5f) * scaleX)); - if (sourceX < 0) - { - sourceX = 0; // Should never happen - } - else if (sourceX >= static_cast(sourceWidth)) - { - sourceX = sourceWidth - 1; - } - - lookupX[x] = static_cast(sourceX); - } - - std::vector lookupY(targetHeight); - - for (unsigned int y = 0; y < targetHeight; y++) - { - int sourceY = static_cast(std::floor((static_cast(y) + 0.5f) * scaleY)); - if (sourceY < 0) - { - sourceY = 0; // Should never happen - } - else if (sourceY >= static_cast(sourceHeight)) - { - sourceY = sourceHeight - 1; - } - - lookupY[y] = static_cast(sourceY); - } - - - /** - * Actual resizing - **/ - - for (unsigned int targetY = 0; targetY < targetHeight; targetY++) - { - unsigned int sourceY = lookupY[targetY]; - - for (unsigned int targetX = 0; targetX < targetWidth; targetX++) - { - unsigned int sourceX = lookupX[targetX]; - - typename ImageTraits::PixelType pixel; - ImageTraits::GetPixel(pixel, source, sourceX, sourceY); - ImageTraits::SetPixel(target, pixel, targetX, targetY); - } - } - } - - - - void ImageProcessing::Resize(ImageAccessor& target, - const ImageAccessor& source) - { - if (source.GetFormat() != source.GetFormat()) - { - throw OrthancException(ErrorCode_IncompatibleImageFormat); - } - - if (source.GetWidth() == target.GetWidth() && - source.GetHeight() == target.GetHeight()) - { - Copy(target, source); - return; - } - - switch (source.GetFormat()) - { - case PixelFormat_Grayscale8: - ResizeInternal(target, source); - break; - - case PixelFormat_Float32: - ResizeInternal(target, source); - break; - - case PixelFormat_RGB24: - ResizeInternal(target, source); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - ImageAccessor* ImageProcessing::Halve(const ImageAccessor& source, - bool forceMinimalPitch) - { - std::unique_ptr target(new Image(source.GetFormat(), source.GetWidth() / 2, - source.GetHeight() / 2, forceMinimalPitch)); - Resize(*target, source); - return target.release(); - } - - - template - static void FlipXInternal(ImageAccessor& image) - { - const unsigned int height = image.GetHeight(); - const unsigned int width = image.GetWidth(); - - for (unsigned int y = 0; y < height; y++) - { - for (unsigned int x1 = 0; x1 < width / 2; x1++) - { - unsigned int x2 = width - 1 - x1; - - typename ImageTraits::PixelType a, b; - ImageTraits::GetPixel(a, image, x1, y); - ImageTraits::GetPixel(b, image, x2, y); - ImageTraits::SetPixel(image, a, x2, y); - ImageTraits::SetPixel(image, b, x1, y); - } - } - } - - - void ImageProcessing::FlipX(ImageAccessor& image) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - FlipXInternal(image); - break; - - case PixelFormat_RGB24: - FlipXInternal(image); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - template - static void FlipYInternal(ImageAccessor& image) - { - const unsigned int height = image.GetHeight(); - const unsigned int width = image.GetWidth(); - - for (unsigned int y1 = 0; y1 < height / 2; y1++) - { - unsigned int y2 = height - 1 - y1; - - for (unsigned int x = 0; x < width; x++) - { - typename ImageTraits::PixelType a, b; - ImageTraits::GetPixel(a, image, x, y1); - ImageTraits::GetPixel(b, image, x, y2); - ImageTraits::SetPixel(image, a, x, y2); - ImageTraits::SetPixel(image, b, x, y1); - } - } - } - - - void ImageProcessing::FlipY(ImageAccessor& image) - { - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - FlipYInternal(image); - break; - - case PixelFormat_RGB24: - FlipYInternal(image); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - // This is a slow implementation of horizontal convolution on one - // individual channel, that checks for out-of-image values - template - static float GetHorizontalConvolutionFloatSecure(const Orthanc::ImageAccessor& source, - const std::vector& horizontal, - size_t horizontalAnchor, - unsigned int x, - unsigned int y, - float leftBorder, - float rightBorder, - unsigned int channel) - { - const RawPixel* row = reinterpret_cast(source.GetConstRow(y)) + channel; - - float p = 0; - - for (unsigned int k = 0; k < horizontal.size(); k++) - { - float value; - - if (x + k < horizontalAnchor) // Negation of "x - horizontalAnchor + k >= 0" - { - value = leftBorder; - } - else if (x + k >= source.GetWidth() + horizontalAnchor) // Negation of "x - horizontalAnchor + k < width" - { - value = rightBorder; - } - else - { - // The value lies within the image - value = row[(x - horizontalAnchor + k) * ChannelsCount]; - } - - p += value * horizontal[k]; - } - - return p; - } - - - - // This is an implementation of separable convolution that uses - // floating-point arithmetics, and an intermediate Float32 - // image. The out-of-image values are taken as the border - // value. Further optimization is possible. - template - static void SeparableConvolutionFloat(ImageAccessor& image /* inplace */, - const std::vector& horizontal, - size_t horizontalAnchor, - const std::vector& vertical, - size_t verticalAnchor, - float normalization) - { - // WARNING - "::min()" should be replaced by "::lowest()" if - // dealing with float or double (which is not the case so far) - assert(sizeof(RawPixel) <= 2); // Safeguard to remember about "float/double" - - const unsigned int width = image.GetWidth(); - const unsigned int height = image.GetHeight(); - - - /** - * Horizontal convolution - **/ - - Image tmp(PixelFormat_Float32, ChannelsCount * width, height, false); - - for (unsigned int y = 0; y < height; y++) - { - const RawPixel* row = reinterpret_cast(image.GetConstRow(y)); - - float leftBorder[ChannelsCount], rightBorder[ChannelsCount]; - - for (unsigned int c = 0; c < ChannelsCount; c++) - { - leftBorder[c] = row[c]; - rightBorder[c] = row[ChannelsCount * (width - 1) + c]; - } - - float* p = static_cast(tmp.GetRow(y)); - - if (width < horizontal.size()) - { - // It is not possible to have the full kernel within the image, use the direct implementation - for (unsigned int x = 0; x < width; x++) - { - for (unsigned int c = 0; c < ChannelsCount; c++, p++) - { - *p = GetHorizontalConvolutionFloatSecure - (image, horizontal, horizontalAnchor, x, y, leftBorder[c], rightBorder[c], c); - } - } - } - else - { - // Deal with the left border - for (unsigned int x = 0; x < horizontalAnchor; x++) - { - for (unsigned int c = 0; c < ChannelsCount; c++, p++) - { - *p = GetHorizontalConvolutionFloatSecure - (image, horizontal, horizontalAnchor, x, y, leftBorder[c], rightBorder[c], c); - } - } - - // Deal with the central portion of the image (all pixel values - // scanned by the kernel lie inside the image) - - for (unsigned int x = 0; x < width - horizontal.size() + 1; x++) - { - for (unsigned int c = 0; c < ChannelsCount; c++, p++) - { - *p = 0; - for (unsigned int k = 0; k < horizontal.size(); k++) - { - *p += static_cast(row[(x + k) * ChannelsCount + c]) * horizontal[k]; - } - } - } - - // Deal with the right border - for (unsigned int x = static_cast( - horizontalAnchor + width - horizontal.size() + 1); x < width; x++) - { - for (unsigned int c = 0; c < ChannelsCount; c++, p++) - { - *p = GetHorizontalConvolutionFloatSecure - (image, horizontal, horizontalAnchor, x, y, leftBorder[c], rightBorder[c], c); - } - } - } - } - - - /** - * Vertical convolution - **/ - - std::vector rows(vertical.size()); - - for (unsigned int y = 0; y < height; y++) - { - for (unsigned int k = 0; k < vertical.size(); k++) - { - if (y + k < verticalAnchor) - { - rows[k] = reinterpret_cast(tmp.GetConstRow(0)); // Use top border - } - else if (y + k >= height + verticalAnchor) - { - rows[k] = reinterpret_cast(tmp.GetConstRow(height - 1)); // Use bottom border - } - else - { - rows[k] = reinterpret_cast(tmp.GetConstRow(static_cast(y + k - verticalAnchor))); - } - } - - RawPixel* p = reinterpret_cast(image.GetRow(y)); - - for (unsigned int x = 0; x < width; x++) - { - for (unsigned int c = 0; c < ChannelsCount; c++, p++) - { - float accumulator = 0; - - for (unsigned int k = 0; k < vertical.size(); k++) - { - accumulator += rows[k][ChannelsCount * x + c] * vertical[k]; - } - - accumulator *= normalization; - - if (accumulator <= static_cast(std::numeric_limits::min())) - { - *p = std::numeric_limits::min(); - } - else if (accumulator >= static_cast(std::numeric_limits::max())) - { - *p = std::numeric_limits::max(); - } - else - { - *p = static_cast(accumulator); - } - } - } - } - } - - - void ImageProcessing::SeparableConvolution(ImageAccessor& image /* inplace */, - const std::vector& horizontal, - size_t horizontalAnchor, - const std::vector& vertical, - size_t verticalAnchor) - { - if (horizontal.size() == 0 || - vertical.size() == 0 || - horizontalAnchor >= horizontal.size() || - verticalAnchor >= vertical.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (image.GetWidth() == 0 || - image.GetHeight() == 0) - { - return; - } - - /** - * Compute normalization - **/ - - float sumHorizontal = 0; - for (size_t i = 0; i < horizontal.size(); i++) - { - sumHorizontal += horizontal[i]; - } - - float sumVertical = 0; - for (size_t i = 0; i < vertical.size(); i++) - { - sumVertical += vertical[i]; - } - - if (fabsf(sumHorizontal) <= std::numeric_limits::epsilon() || - fabsf(sumVertical) <= std::numeric_limits::epsilon()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, "Singular convolution kernel"); - } - - const float normalization = 1.0f / (sumHorizontal * sumVertical); - - switch (image.GetFormat()) - { - case PixelFormat_Grayscale8: - SeparableConvolutionFloat - (image, horizontal, horizontalAnchor, vertical, verticalAnchor, normalization); - break; - - case PixelFormat_RGB24: - SeparableConvolutionFloat - (image, horizontal, horizontalAnchor, vertical, verticalAnchor, normalization); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void ImageProcessing::SmoothGaussian5x5(ImageAccessor& image) - { - std::vector kernel(5); - kernel[0] = 1; - kernel[1] = 4; - kernel[2] = 6; - kernel[3] = 4; - kernel[4] = 1; - - SeparableConvolution(image, kernel, 2, kernel, 2); - } - - - void ImageProcessing::FitSize(ImageAccessor& target, - const ImageAccessor& source) - { - if (target.GetWidth() == 0 || - target.GetHeight() == 0) - { - return; - } - - if (source.GetWidth() == target.GetWidth() && - source.GetHeight() == target.GetHeight()) - { - Copy(target, source); - return; - } - - Set(target, 0); - - // Preserve the aspect ratio - float cw = static_cast(source.GetWidth()); - float ch = static_cast(source.GetHeight()); - float r = std::min( - static_cast(target.GetWidth()) / cw, - static_cast(target.GetHeight()) / ch); - - unsigned int sw = std::min(static_cast(boost::math::iround(cw * r)), target.GetWidth()); - unsigned int sh = std::min(static_cast(boost::math::iround(ch * r)), target.GetHeight()); - Image resized(target.GetFormat(), sw, sh, false); - - //ImageProcessing::SmoothGaussian5x5(source); - ImageProcessing::Resize(resized, source); - - assert(target.GetWidth() >= resized.GetWidth() && - target.GetHeight() >= resized.GetHeight()); - unsigned int offsetX = (target.GetWidth() - resized.GetWidth()) / 2; - unsigned int offsetY = (target.GetHeight() - resized.GetHeight()) / 2; - - ImageAccessor region; - target.GetRegion(region, offsetX, offsetY, resized.GetWidth(), resized.GetHeight()); - ImageProcessing::Copy(region, resized); - } - - - ImageAccessor* ImageProcessing::FitSize(const ImageAccessor& source, - unsigned int width, - unsigned int height) - { - std::unique_ptr target(new Image(source.GetFormat(), width, height, false)); - FitSize(*target, source); - return target.release(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageProcessing.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,192 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ImageAccessor.h" -#include - -#include -#include - -namespace Orthanc -{ - namespace ImageProcessing - { - class ImagePoint - { - int32_t x_; - int32_t y_; - - public: - ImagePoint(int32_t x, int32_t y) - : x_(x), - y_(y) - { - } - - int32_t GetX() const {return x_;} - - int32_t GetY() const {return y_;} - - void Set(int32_t x, int32_t y) - { - x_ = x; - y_ = y; - } - - void ClipTo(int32_t minX, int32_t maxX, int32_t minY, int32_t maxY) - { - x_ = std::max(minX, std::min(maxX, x_)); - y_ = std::max(minY, std::min(maxY, y_)); - } - - double GetDistanceTo(const ImagePoint& other) const; - - double GetDistanceToLine(double a, double b, double c) const; // where ax + by + c = 0 is the equation of the line - }; - - void Copy(ImageAccessor& target, - const ImageAccessor& source); - - void Convert(ImageAccessor& target, - const ImageAccessor& source); - - void ApplyWindowing_Deprecated(ImageAccessor& target, - const ImageAccessor& source, - float windowCenter, - float windowWidth, - float rescaleSlope, - float rescaleIntercept, - bool invert); - - void Set(ImageAccessor& image, - int64_t value); - - void Set(ImageAccessor& image, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha); - - void Set(ImageAccessor& image, - uint8_t red, - uint8_t green, - uint8_t blue, - ImageAccessor& alpha); - - void ShiftRight(ImageAccessor& target, - unsigned int shift); - - void ShiftLeft(ImageAccessor& target, - unsigned int shift); - - void GetMinMaxIntegerValue(int64_t& minValue, - int64_t& maxValue, - const ImageAccessor& image); - - void GetMinMaxFloatValue(float& minValue, - float& maxValue, - const ImageAccessor& image); - - void AddConstant(ImageAccessor& image, - int64_t value); - - // "useRound" is expensive - void MultiplyConstant(ImageAccessor& image, - float factor, - bool useRound); - - // Computes "(x + offset) * scaling" inplace. "useRound" is expensive. - void ShiftScale(ImageAccessor& image, - float offset, - float scaling, - bool useRound); - - void ShiftScale(ImageAccessor& target, - const ImageAccessor& source, - float offset, - float scaling, - bool useRound); - - void Invert(ImageAccessor& image); - - void Invert(ImageAccessor& image, int64_t maxValue); - - void DrawLineSegment(ImageAccessor& image, - int x0, - int y0, - int x1, - int y1, - int64_t value); - - void DrawLineSegment(ImageAccessor& image, - int x0, - int y0, - int x1, - int y1, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha); - - void FillPolygon(ImageAccessor& image, - const std::vector& points, - int64_t value); - - void Resize(ImageAccessor& target, - const ImageAccessor& source); - - ImageAccessor* Halve(const ImageAccessor& source, - bool forceMinimalPitch); - - void FlipX(ImageAccessor& image); - - void FlipY(ImageAccessor& image); - - void SeparableConvolution(ImageAccessor& image /* inplace */, - const std::vector& horizontal, - size_t horizontalAnchor, - const std::vector& vertical, - size_t verticalAnchor); - - void SmoothGaussian5x5(ImageAccessor& image); - - void FitSize(ImageAccessor& target, - const ImageAccessor& source); - - ImageAccessor* FitSize(const ImageAccessor& source, - unsigned int width, - unsigned int height); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageTraits.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageTraits.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageTraits.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/ImageTraits.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ImageAccessor.h" -#include "PixelTraits.h" - -#include - -namespace Orthanc -{ - template - struct ImageTraits - { - typedef ::Orthanc::PixelTraits PixelTraits; - typedef typename PixelTraits::PixelType PixelType; - - static PixelFormat GetPixelFormat() - { - return Format; - } - - static void GetPixel(PixelType& target, - const ImageAccessor& image, - unsigned int x, - unsigned int y) - { - assert(x < image.GetWidth() && y < image.GetHeight()); - PixelTraits::Copy(target, image.GetPixelUnchecked(x, y)); - } - - static void SetPixel(ImageAccessor& image, - const PixelType& value, - unsigned int x, - unsigned int y) - { - assert(x < image.GetWidth() && y < image.GetHeight()); - PixelTraits::Copy(image.GetPixelUnchecked(x, y), value); - } - - static float GetFloatPixel(const ImageAccessor& image, - unsigned int x, - unsigned int y) - { - assert(x < image.GetWidth() && y < image.GetHeight()); - return PixelTraits::PixelToFloat(image.GetPixelUnchecked(x, y)); - } - - static void SetFloatPixel(ImageAccessor& image, - float value, - unsigned int x, - unsigned int y) - { - assert(x < image.GetWidth() && y < image.GetHeight()); - PixelTraits::FloatToPixel(image.GetPixelUnchecked(x, y), value); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JpegErrorManager.h" - -namespace Orthanc -{ - namespace Internals - { - void JpegErrorManager::OutputMessage(j_common_ptr cinfo) - { - char message[JMSG_LENGTH_MAX]; - (*cinfo->err->format_message) (cinfo, message); - - JpegErrorManager* that = reinterpret_cast(cinfo->err); - that->message = std::string(message); - } - - - void JpegErrorManager::ErrorExit(j_common_ptr cinfo) - { - (*cinfo->err->output_message) (cinfo); - - JpegErrorManager* that = reinterpret_cast(cinfo->err); - longjmp(that->setjmp_buffer, 1); - } - - - JpegErrorManager::JpegErrorManager() - { - memset(&pub, 0, sizeof(struct jpeg_error_mgr)); - memset(&setjmp_buffer, 0, sizeof(jmp_buf)); - - jpeg_std_error(&pub); - pub.error_exit = ErrorExit; - pub.output_message = OutputMessage; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegErrorManager.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#if !defined(ORTHANC_ENABLE_JPEG) -# error The macro ORTHANC_ENABLE_JPEG must be defined -#endif - -#if ORTHANC_ENABLE_JPEG != 1 -# error JPEG support must be enabled to include this file -#endif - -#include -#include -#include -#include -#include - -namespace Orthanc -{ - namespace Internals - { - class JpegErrorManager - { - private: - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ - std::string message; - - static void OutputMessage(j_common_ptr cinfo); - - static void ErrorExit(j_common_ptr cinfo); - - public: - JpegErrorManager(); - - struct jpeg_error_mgr* GetPublic() - { - return &pub; - } - - jmp_buf& GetJumpBuffer() - { - return setjmp_buffer; - } - - const std::string& GetMessage() const - { - return message; - } - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JpegReader.h" - -#include "JpegErrorManager.h" -#include "../OrthancException.h" -#include "../Logging.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - - -namespace Orthanc -{ - static void Uncompress(struct jpeg_decompress_struct& cinfo, - std::string& content, - ImageAccessor& accessor) - { - // The "static_cast" is necessary on OS X: - // https://github.com/simonfuhrmann/mve/issues/371 - jpeg_read_header(&cinfo, static_cast(true)); - - jpeg_start_decompress(&cinfo); - - PixelFormat format; - if (cinfo.output_components == 1 && - cinfo.out_color_space == JCS_GRAYSCALE) - { - format = PixelFormat_Grayscale8; - } - else if (cinfo.output_components == 3 && - cinfo.out_color_space == JCS_RGB) - { - format = PixelFormat_RGB24; - } - else - { - throw OrthancException(ErrorCode_NotImplemented); - } - - unsigned int pitch = cinfo.output_width * cinfo.output_components; - - /* Make a one-row-high sample array that will go away when done with image */ - JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, pitch, 1); - - try - { - content.resize(pitch * cinfo.output_height); - } - catch (...) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - accessor.AssignWritable(format, cinfo.output_width, cinfo.output_height, pitch, - content.empty() ? NULL : &content[0]); - - uint8_t* target = reinterpret_cast(&content[0]); - while (cinfo.output_scanline < cinfo.output_height) - { - jpeg_read_scanlines(&cinfo, buffer, 1); - memcpy(target, buffer[0], pitch); - target += pitch; - } - - // Everything went fine, "setjmp()" didn't get called - - jpeg_finish_decompress(&cinfo); - } - - -#if ORTHANC_SANDBOXED == 0 - void JpegReader::ReadFromFile(const std::string& filename) - { - FILE* fp = SystemToolbox::OpenFile(filename, FileMode_ReadBinary); - if (!fp) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - struct jpeg_decompress_struct cinfo; - memset(&cinfo, 0, sizeof(struct jpeg_decompress_struct)); - - Internals::JpegErrorManager jerr; - cinfo.err = jerr.GetPublic(); - - if (setjmp(jerr.GetJumpBuffer())) - { - jpeg_destroy_decompress(&cinfo); - fclose(fp); - - throw OrthancException(ErrorCode_InternalError, - "Error during JPEG decoding: " + jerr.GetMessage()); - } - - // Below this line, we are under the scope of a "setjmp" - - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, fp); - - try - { - Uncompress(cinfo, content_, *this); - } - catch (OrthancException&) - { - jpeg_destroy_decompress(&cinfo); - fclose(fp); - throw; - } - - jpeg_destroy_decompress(&cinfo); - fclose(fp); - } -#endif - - - void JpegReader::ReadFromMemory(const void* buffer, - size_t size) - { - struct jpeg_decompress_struct cinfo; - memset(&cinfo, 0, sizeof(struct jpeg_decompress_struct)); - - Internals::JpegErrorManager jerr; - cinfo.err = jerr.GetPublic(); - - if (setjmp(jerr.GetJumpBuffer())) - { - jpeg_destroy_decompress(&cinfo); - throw OrthancException(ErrorCode_InternalError, - "Error during JPEG decoding: " + jerr.GetMessage()); - } - - // Below this line, we are under the scope of a "setjmp" - jpeg_create_decompress(&cinfo); - jpeg_mem_src(&cinfo, - const_cast( - reinterpret_cast(buffer)), - static_cast(size)); - - try - { - Uncompress(cinfo, content_, *this); - } - catch (OrthancException&) - { - jpeg_destroy_decompress(&cinfo); - throw; - } - - jpeg_destroy_decompress(&cinfo); - } - - - void JpegReader::ReadFromMemory(const std::string& buffer) - { - if (buffer.empty()) - { - ReadFromMemory(NULL, 0); - } - else - { - ReadFromMemory(buffer.c_str(), buffer.size()); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegReader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if !defined(ORTHANC_ENABLE_JPEG) -# error The macro ORTHANC_ENABLE_JPEG must be defined -#endif - -#if ORTHANC_ENABLE_JPEG != 1 -# error JPEG support must be enabled to include this file -#endif - -#include "ImageAccessor.h" - -#include - -namespace Orthanc -{ - class JpegReader : public ImageAccessor - { - private: - std::string content_; - - public: -#if ORTHANC_SANDBOXED == 0 - void ReadFromFile(const std::string& filename); -#endif - - void ReadFromMemory(const void* buffer, - size_t size); - - void ReadFromMemory(const std::string& buffer); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,213 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JpegWriter.h" - -#include "../OrthancException.h" -#include "../Logging.h" -#include "JpegErrorManager.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - -#include -#include - -namespace Orthanc -{ - static void GetLines(std::vector& lines, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - if (format != PixelFormat_Grayscale8 && - format != PixelFormat_RGB24) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - lines.resize(height); - - uint8_t* base = const_cast(reinterpret_cast(buffer)); - for (unsigned int y = 0; y < height; y++) - { - lines[y] = base + static_cast(y) * static_cast(pitch); - } - } - - - static void Compress(struct jpeg_compress_struct& cinfo, - std::vector& lines, - unsigned int width, - unsigned int height, - PixelFormat format, - uint8_t quality) - { - cinfo.image_width = width; - cinfo.image_height = height; - - switch (format) - { - case PixelFormat_Grayscale8: - cinfo.input_components = 1; - cinfo.in_color_space = JCS_GRAYSCALE; - break; - - case PixelFormat_RGB24: - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - jpeg_set_defaults(&cinfo); - - // The "static_cast" is necessary on OS X: - // https://github.com/simonfuhrmann/mve/issues/371 - jpeg_set_quality(&cinfo, quality, static_cast(true)); - jpeg_start_compress(&cinfo, static_cast(true)); - - jpeg_write_scanlines(&cinfo, &lines[0], height); - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - } - - - void JpegWriter::SetQuality(uint8_t quality) - { - if (quality == 0 || quality > 100) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - quality_ = quality; - } - - -#if ORTHANC_SANDBOXED == 0 - void JpegWriter::WriteToFileInternal(const std::string& filename, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary); - if (fp == NULL) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - std::vector lines; - GetLines(lines, height, pitch, format, buffer); - - struct jpeg_compress_struct cinfo; - memset(&cinfo, 0, sizeof(struct jpeg_compress_struct)); - - Internals::JpegErrorManager jerr; - cinfo.err = jerr.GetPublic(); - - if (setjmp(jerr.GetJumpBuffer())) - { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_compress(&cinfo); - fclose(fp); - throw OrthancException(ErrorCode_InternalError, - "Error during JPEG encoding: " + jerr.GetMessage()); - } - - // Do not allocate data on the stack below this line! - - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, fp); - Compress(cinfo, lines, width, height, format, quality_); - - // Everything went fine, "setjmp()" didn't get called - - fclose(fp); - } -#endif - - - void JpegWriter::WriteToMemoryInternal(std::string& jpeg, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - std::vector lines; - GetLines(lines, height, pitch, format, buffer); - - struct jpeg_compress_struct cinfo; - memset(&cinfo, 0, sizeof(struct jpeg_compress_struct)); - - Internals::JpegErrorManager jerr; - - unsigned char* data = NULL; - unsigned long size; - - if (setjmp(jerr.GetJumpBuffer())) - { - jpeg_destroy_compress(&cinfo); - - if (data != NULL) - { - free(data); - } - - throw OrthancException(ErrorCode_InternalError, - "Error during JPEG encoding: " + jerr.GetMessage()); - } - - // Do not allocate data on the stack below this line! - - jpeg_create_compress(&cinfo); - cinfo.err = jerr.GetPublic(); - jpeg_mem_dest(&cinfo, &data, &size); - - Compress(cinfo, lines, width, height, format, quality_); - - // Everything went fine, "setjmp()" didn't get called - - jpeg.assign(reinterpret_cast(data), size); - free(data); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/JpegWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_JPEG) -# error The macro ORTHANC_ENABLE_JPEG must be defined -#endif - -#if ORTHANC_ENABLE_JPEG != 1 -# error JPEG support must be enabled to include this file -#endif - -#include "IImageWriter.h" - -namespace Orthanc -{ - class JpegWriter : public IImageWriter - { - protected: -#if ORTHANC_SANDBOXED == 0 - virtual void WriteToFileInternal(const std::string& filename, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); -#endif - - virtual void WriteToMemoryInternal(std::string& jpeg, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - - private: - uint8_t quality_; - - public: - JpegWriter() : quality_(90) - { - } - - void SetQuality(uint8_t quality); - - uint8_t GetQuality() const - { - return quality_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,309 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "PamReader.h" - -#include "../Endianness.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - -#include // For malloc/free -#include -#include - - -namespace Orthanc -{ - static void GetPixelFormat(PixelFormat& format, - unsigned int& bytesPerChannel, - const unsigned int& maxValue, - const unsigned int& channelCount, - const std::string& tupleType) - { - if (tupleType == "GRAYSCALE" && - channelCount == 1) - { - switch (maxValue) - { - case 255: - format = PixelFormat_Grayscale8; - bytesPerChannel = 1; - return; - - case 65535: - format = PixelFormat_Grayscale16; - bytesPerChannel = 2; - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - else if (tupleType == "RGB" && - channelCount == 3) - { - switch (maxValue) - { - case 255: - format = PixelFormat_RGB24; - bytesPerChannel = 1; - return; - - case 65535: - format = PixelFormat_RGB48; - bytesPerChannel = 2; - return; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - else - { - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - typedef std::map Parameters; - - - static std::string LookupStringParameter(const Parameters& parameters, - const std::string& key) - { - Parameters::const_iterator found = parameters.find(key); - - if (found == parameters.end()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - return found->second; - } - } - - - static unsigned int LookupIntegerParameter(const Parameters& parameters, - const std::string& key) - { - try - { - int value = boost::lexical_cast(LookupStringParameter(parameters, key)); - - if (value < 0) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - return static_cast(value); - } - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - void PamReader::ParseContent() - { - static const std::string headerDelimiter = "ENDHDR\n"; - - boost::iterator_range headerRange = - boost::algorithm::find_first(content_, headerDelimiter); - - if (!headerRange) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - std::string header(static_cast(content_).begin(), headerRange.begin()); - - std::vector lines; - Toolbox::TokenizeString(lines, header, '\n'); - - if (lines.size() < 2 || - lines.front() != "P7" || - !lines.back().empty()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Parameters parameters; - - for (size_t i = 1; i + 1 < lines.size(); i++) - { - std::vector tokens; - Toolbox::TokenizeString(tokens, lines[i], ' '); - - if (tokens.size() != 2) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - parameters[tokens[0]] = tokens[1]; - } - } - - const unsigned int width = LookupIntegerParameter(parameters, "WIDTH"); - const unsigned int height = LookupIntegerParameter(parameters, "HEIGHT"); - const unsigned int channelCount = LookupIntegerParameter(parameters, "DEPTH"); - const unsigned int maxValue = LookupIntegerParameter(parameters, "MAXVAL"); - const std::string tupleType = LookupStringParameter(parameters, "TUPLTYPE"); - - unsigned int bytesPerChannel; - PixelFormat format; - GetPixelFormat(format, bytesPerChannel, maxValue, channelCount, tupleType.c_str()); - - unsigned int pitch = width * channelCount * bytesPerChannel; - - if (content_.size() != header.size() + headerDelimiter.size() + pitch * height) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - size_t offset = content_.size() - pitch * height; - - { - intptr_t bufferAddr = reinterpret_cast(&content_[offset]); - if((bufferAddr % 8) == 0) - LOG(TRACE) << "PamReader::ParseContent() image address = " << bufferAddr; - else - LOG(TRACE) << "PamReader::ParseContent() image address = " << bufferAddr << " (not a multiple of 8!)"; - } - - // if we want to enforce alignment, we need to use a freshly allocated - // buffer, since we have no alignment guarantees on the original one - if (enforceAligned_) - { - if (alignedImageBuffer_ != NULL) - free(alignedImageBuffer_); - alignedImageBuffer_ = malloc(pitch * height); - memcpy(alignedImageBuffer_, &content_[offset], pitch* height); - content_ = ""; - AssignWritable(format, width, height, pitch, alignedImageBuffer_); - } - else - { - AssignWritable(format, width, height, pitch, &content_[offset]); - } - - // Byte swapping if needed - if (bytesPerChannel != 1 && - bytesPerChannel != 2) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - if (Toolbox::DetectEndianness() == Endianness_Little && - bytesPerChannel == 2) - { - for (unsigned int h = 0; h < height; ++h) - { - uint16_t* pixel = reinterpret_cast(GetRow(h)); - - for (unsigned int w = 0; w < GetWidth(); ++w, ++pixel) - { -#if ORTHANC_ENABLE_WASM == 1 - /* - - crash (2019-08-05): - - Uncaught abort(alignment fault) at Error - at jsStackTrace - at stackTrace - at abort - at alignfault - at SAFE_HEAP_LOAD_i32_2_2 (wasm-function[251132]:39) - at __ZN7Orthanc9PamReader12ParseContentEv (wasm-function[11457]:8088) - - Web Assembly IS LITTLE ENDIAN! - - Perhaps in htobe16 ? - */ - uint8_t* srcdst = reinterpret_cast(pixel); - uint8_t tmp = srcdst[0]; - srcdst[0] = srcdst[1]; - srcdst[1] = tmp; -#else - // memcpy() is necessary to avoid segmentation fault if the - // "pixel" pointer is not 16-bit aligned (which is the case - // if "offset" is an odd number). Check out issue #99: - // https://bitbucket.org/sjodogne/orthanc/issues/99 - uint16_t v = htobe16(*pixel); - memcpy(pixel, &v, sizeof(v)); -#endif - } - } - } - } - - -#if ORTHANC_SANDBOXED == 0 - void PamReader::ReadFromFile(const std::string& filename) - { - SystemToolbox::ReadFile(content_, filename); - ParseContent(); - } -#endif - - - void PamReader::ReadFromMemory(const std::string& buffer) - { - content_ = buffer; - ParseContent(); - } - - void PamReader::ReadFromMemory(const void* buffer, - size_t size) - { - content_.assign(reinterpret_cast(buffer), size); - ParseContent(); - } - - PamReader::~PamReader() - { - if (alignedImageBuffer_ != NULL) - { - free(alignedImageBuffer_); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamReader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,94 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ImageAccessor.h" - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -namespace Orthanc -{ - class PamReader : public ImageAccessor - { - private: - void ParseContent(); - - /** - Whether we want to use the default malloc alignment in the image buffer, - at the expense of an extra copy - */ - bool enforceAligned_; - - /** - This is actually a copy of wrappedContent_, but properly aligned. - - It is only used if the enforceAligned parameter is set to true in the - constructor. - */ - void* alignedImageBuffer_; - - /** - Points somewhere in the content_ buffer. - */ - ImageAccessor wrappedContent_; - - /** - Raw content (file bytes or answer from the server, for instance). - */ - std::string content_; - - public: - /** - See doc for field enforceAligned_ - */ - PamReader(bool enforceAligned = false) : - enforceAligned_(enforceAligned), - alignedImageBuffer_(NULL) - { - } - - virtual ~PamReader(); - -#if ORTHANC_SANDBOXED == 0 - void ReadFromFile(const std::string& filename); -#endif - - void ReadFromMemory(const std::string& buffer); - - void ReadFromMemory(const void* buffer, - size_t size); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "PamWriter.h" - -#include "../Endianness.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#include - - -namespace Orthanc -{ - static void GetPixelFormatInfo(const PixelFormat& format, - unsigned int& maxValue, - unsigned int& channelCount, - unsigned int& bytesPerChannel, - std::string& tupleType) - { - switch (format) - { - case PixelFormat_Grayscale8: - maxValue = 255; - channelCount = 1; - bytesPerChannel = 1; - tupleType = "GRAYSCALE"; - break; - - case PixelFormat_SignedGrayscale16: - case PixelFormat_Grayscale16: - maxValue = 65535; - channelCount = 1; - bytesPerChannel = 2; - tupleType = "GRAYSCALE"; - break; - - case PixelFormat_RGB24: - maxValue = 255; - channelCount = 3; - bytesPerChannel = 1; - tupleType = "RGB"; - break; - - case PixelFormat_RGB48: - maxValue = 255; - channelCount = 3; - bytesPerChannel = 2; - tupleType = "RGB"; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void PamWriter::WriteToMemoryInternal(std::string& target, - unsigned int width, - unsigned int height, - unsigned int sourcePitch, - PixelFormat format, - const void* buffer) - { - unsigned int maxValue, channelCount, bytesPerChannel; - std::string tupleType; - GetPixelFormatInfo(format, maxValue, channelCount, bytesPerChannel, tupleType); - - target = (std::string("P7") + - std::string("\nWIDTH ") + boost::lexical_cast(width) + - std::string("\nHEIGHT ") + boost::lexical_cast(height) + - std::string("\nDEPTH ") + boost::lexical_cast(channelCount) + - std::string("\nMAXVAL ") + boost::lexical_cast(maxValue) + - std::string("\nTUPLTYPE ") + tupleType + - std::string("\nENDHDR\n")); - - if (bytesPerChannel != 1 && - bytesPerChannel != 2) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - size_t targetPitch = channelCount * bytesPerChannel * width; - size_t offset = target.size(); - - target.resize(offset + targetPitch * height); - - assert(target.size() != 0); - - if (Toolbox::DetectEndianness() == Endianness_Little && - bytesPerChannel == 2) - { - // Byte swapping - for (unsigned int h = 0; h < height; ++h) - { - const uint16_t* p = reinterpret_cast - (reinterpret_cast(buffer) + h * sourcePitch); - uint16_t* q = reinterpret_cast - (reinterpret_cast(&target[offset]) + h * targetPitch); - - for (unsigned int w = 0; w < width * channelCount; ++w) - { - // memcpy() is necessary to avoid segmentation fault if the - // "pixel" pointer is not 16-bit aligned (which is the case - // if "offset" is an odd number). Check out issue #99: - // https://bitbucket.org/sjodogne/orthanc/issues/99 - uint16_t v = htobe16(*p); - memcpy(q, &v, sizeof(uint16_t)); - - p++; - q++; - } - } - } - else - { - // Either "bytesPerChannel == 1" (and endianness is not - // relevant), or we run on a big endian architecture (and no - // byte swapping is necessary, as PAM uses big endian) - - for (unsigned int h = 0; h < height; ++h) - { - const void* p = reinterpret_cast(buffer) + h * sourcePitch; - void* q = reinterpret_cast(&target[offset]) + h * targetPitch; - memcpy(q, p, targetPitch); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PamWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IImageWriter.h" - -namespace Orthanc -{ - // https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format - class PamWriter : public IImageWriter - { - protected: - virtual void WriteToMemoryInternal(std::string& target, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PixelTraits.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PixelTraits.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PixelTraits.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PixelTraits.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,412 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -#include - -namespace Orthanc -{ - template - struct IntegerPixelTraits - { - typedef _PixelType PixelType; - - ORTHANC_FORCE_INLINE - static PixelFormat GetPixelFormat() - { - return format; - } - - ORTHANC_FORCE_INLINE - static PixelType IntegerToPixel(int64_t value) - { - if (value < static_cast(std::numeric_limits::min())) - { - return std::numeric_limits::min(); - } - else if (value > static_cast(std::numeric_limits::max())) - { - return std::numeric_limits::max(); - } - else - { - return static_cast(value); - } - } - - ORTHANC_FORCE_INLINE - static void SetZero(PixelType& target) - { - target = 0; - } - - ORTHANC_FORCE_INLINE - static void SetMinValue(PixelType& target) - { - target = std::numeric_limits::min(); - } - - ORTHANC_FORCE_INLINE - static void SetMaxValue(PixelType& target) - { - target = std::numeric_limits::max(); - } - - ORTHANC_FORCE_INLINE - static void Copy(PixelType& target, - const PixelType& source) - { - target = source; - } - - ORTHANC_FORCE_INLINE - static float PixelToFloat(const PixelType& source) - { - return static_cast(source); - } - - ORTHANC_FORCE_INLINE - static void FloatToPixel(PixelType& target, - float value) - { - value += 0.5f; - if (value < static_cast(std::numeric_limits::min())) - { - target = std::numeric_limits::min(); - } - else if (value > static_cast(std::numeric_limits::max())) - { - target = std::numeric_limits::max(); - } - else - { - target = static_cast(value); - } - } - - ORTHANC_FORCE_INLINE - static bool IsEqual(const PixelType& a, - const PixelType& b) - { - return a == b; - } - }; - - - template - struct PixelTraits; - - - template <> - struct PixelTraits : - public IntegerPixelTraits - { - }; - - - template <> - struct PixelTraits : - public IntegerPixelTraits - { - }; - - - template <> - struct PixelTraits : - public IntegerPixelTraits - { - }; - - - template <> - struct PixelTraits : - public IntegerPixelTraits - { - }; - - - template <> - struct PixelTraits : - public IntegerPixelTraits - { - }; - - - template <> - struct PixelTraits - { - struct PixelType - { - uint8_t red_; - uint8_t green_; - uint8_t blue_; - }; - - ORTHANC_FORCE_INLINE - static PixelFormat GetPixelFormat() - { - return PixelFormat_RGB24; - } - - ORTHANC_FORCE_INLINE - static void SetZero(PixelType& target) - { - target.red_ = 0; - target.green_ = 0; - target.blue_ = 0; - } - - ORTHANC_FORCE_INLINE - static void Copy(PixelType& target, - const PixelType& source) - { - target.red_ = source.red_; - target.green_ = source.green_; - target.blue_ = source.blue_; - } - - ORTHANC_FORCE_INLINE - static bool IsEqual(const PixelType& a, - const PixelType& b) - { - return (a.red_ == b.red_ && - a.green_ == b.green_ && - a.blue_ == b.blue_); - } - - ORTHANC_FORCE_INLINE - static void FloatToPixel(PixelType& target, - float value) - { - uint8_t v; - PixelTraits::FloatToPixel(v, value); - - target.red_ = v; - target.green_ = v; - target.blue_ = v; - } - }; - - - template <> - struct PixelTraits - { - struct PixelType - { - uint8_t blue_; - uint8_t green_; - uint8_t red_; - uint8_t alpha_; - }; - - ORTHANC_FORCE_INLINE - static PixelFormat GetPixelFormat() - { - return PixelFormat_BGRA32; - } - - ORTHANC_FORCE_INLINE - static void SetZero(PixelType& target) - { - target.blue_ = 0; - target.green_ = 0; - target.red_ = 0; - target.alpha_ = 0; - } - - ORTHANC_FORCE_INLINE - static void Copy(PixelType& target, - const PixelType& source) - { - target.blue_ = source.blue_; - target.green_ = source.green_; - target.red_ = source.red_; - target.alpha_ = source.alpha_; - } - - ORTHANC_FORCE_INLINE - static bool IsEqual(const PixelType& a, - const PixelType& b) - { - return (a.blue_ == b.blue_ && - a.green_ == b.green_ && - a.red_ == b.red_ && - a.alpha_ == b.alpha_); - } - - ORTHANC_FORCE_INLINE - static void FloatToPixel(PixelType& target, - float value) - { - uint8_t v; - PixelTraits::FloatToPixel(v, value); - - target.blue_ = v; - target.green_ = v; - target.red_ = v; - target.alpha_ = 255; - } - }; - - - template <> - struct PixelTraits - { - struct PixelType - { - uint8_t red_; - uint8_t green_; - uint8_t blue_; - uint8_t alpha_; - }; - - ORTHANC_FORCE_INLINE - static PixelFormat GetPixelFormat() - { - return PixelFormat_RGBA32; - } - - ORTHANC_FORCE_INLINE - static void SetZero(PixelType& target) - { - target.red_ = 0; - target.green_ = 0; - target.blue_ = 0; - target.alpha_ = 0; - } - - ORTHANC_FORCE_INLINE - static void Copy(PixelType& target, - const PixelType& source) - { - target.red_ = source.red_; - target.green_ = source.green_; - target.blue_ = source.blue_; - target.alpha_ = source.alpha_; - } - - ORTHANC_FORCE_INLINE - static bool IsEqual(const PixelType& a, - const PixelType& b) - { - return (a.red_ == b.red_ && - a.green_ == b.green_ && - a.blue_ == b.blue_ && - a.alpha_ == b.alpha_); - } - - ORTHANC_FORCE_INLINE - static void FloatToPixel(PixelType& target, - float value) - { - uint8_t v; - PixelTraits::FloatToPixel(v, value); - - target.red_ = v; - target.green_ = v; - target.blue_ = v; - target.alpha_ = 255; - } - }; - - - template <> - struct PixelTraits - { - typedef float PixelType; - - ORTHANC_FORCE_INLINE - static PixelFormat GetPixelFormat() - { - return PixelFormat_Float32; - } - - ORTHANC_FORCE_INLINE - static void SetZero(PixelType& target) - { - target = 0.0f; - } - - ORTHANC_FORCE_INLINE - static void Copy(PixelType& target, - const PixelType& source) - { - target = source; - } - - ORTHANC_FORCE_INLINE - static bool IsEqual(const PixelType& a, - const PixelType& b) - { - float tmp = (a - b); - - if (tmp < 0) - { - tmp = -tmp; - } - - return tmp <= std::numeric_limits::epsilon(); - } - - ORTHANC_FORCE_INLINE - static void SetMinValue(PixelType& target) - { - // std::numeric_limits::lowest is not supported on - // all compilers (for instance, Visual Studio 9.0 2008) - target = -std::numeric_limits::max(); - } - - ORTHANC_FORCE_INLINE - static void SetMaxValue(PixelType& target) - { - target = std::numeric_limits::max(); - } - - ORTHANC_FORCE_INLINE - static void FloatToPixel(PixelType& target, - float value) - { - target = value; - } - - ORTHANC_FORCE_INLINE - static float PixelToFloat(const PixelType& source) - { - return source; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,325 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "PngReader.h" - -#include "../OrthancException.h" -#include "../Toolbox.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - -#include -#include // For memcpy() - -namespace Orthanc -{ -#if ORTHANC_SANDBOXED == 0 - namespace - { - struct FileRabi - { - FILE* fp_; - - FileRabi(const char* filename) - { - fp_ = SystemToolbox::OpenFile(filename, FileMode_ReadBinary); - if (!fp_) - { - throw OrthancException(ErrorCode_InexistentFile); - } - } - - ~FileRabi() - { - if (fp_) - { - fclose(fp_); - } - } - }; - } -#endif - - - struct PngReader::PngRabi - { - png_structp png_; - png_infop info_; - png_infop endInfo_; - - void Destruct() - { - if (png_) - { - png_destroy_read_struct(&png_, &info_, &endInfo_); - - png_ = NULL; - info_ = NULL; - endInfo_ = NULL; - } - } - - PngRabi() - { - png_ = NULL; - info_ = NULL; - endInfo_ = NULL; - - png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - info_ = png_create_info_struct(png_); - if (!info_) - { - png_destroy_read_struct(&png_, NULL, NULL); - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - endInfo_ = png_create_info_struct(png_); - if (!info_) - { - png_destroy_read_struct(&png_, &info_, NULL); - throw OrthancException(ErrorCode_NotEnoughMemory); - } - } - - ~PngRabi() - { - Destruct(); - } - - static void MemoryCallback(png_structp png_ptr, - png_bytep data, - png_size_t size); - }; - - - void PngReader::CheckHeader(const void* header) - { - int is_png = !png_sig_cmp((png_bytep) header, 0, 8); - if (!is_png) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - PngReader::PngReader() - { - } - - void PngReader::Read(PngRabi& rabi) - { - png_set_sig_bytes(rabi.png_, 8); - - png_read_info(rabi.png_, rabi.info_); - - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - int compression_type, filter_method; - // get size and bit-depth of the PNG-image - png_get_IHDR(rabi.png_, rabi.info_, - &width, &height, - &bit_depth, &color_type, &interlace_type, - &compression_type, &filter_method); - - PixelFormat format; - unsigned int pitch; - - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 8) - { - format = PixelFormat_Grayscale8; - pitch = width; - } - else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16) - { - format = PixelFormat_Grayscale16; - pitch = 2 * width; - - if (Toolbox::DetectEndianness() == Endianness_Little) - { - png_set_swap(rabi.png_); - } - } - else if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 8) - { - format = PixelFormat_RGB24; - pitch = 3 * width; - } - else if (color_type == PNG_COLOR_TYPE_RGBA && bit_depth == 8) - { - format = PixelFormat_RGBA32; - pitch = 4 * width; - } - else - { - throw OrthancException(ErrorCode_NotImplemented); - } - - data_.resize(height * pitch); - - if (height == 0 || width == 0) - { - // Empty image, we are done - AssignEmpty(format); - return; - } - - png_read_update_info(rabi.png_, rabi.info_); - - std::vector rows(height); - for (size_t i = 0; i < height; i++) - { - rows[i] = &data_[0] + i * pitch; - } - - png_read_image(rabi.png_, &rows[0]); - - AssignWritable(format, width, height, pitch, &data_[0]); - } - - -#if ORTHANC_SANDBOXED == 0 - void PngReader::ReadFromFile(const std::string& filename) - { - FileRabi f(filename.c_str()); - - char header[8]; - if (fread(header, 1, 8, f.fp_) != 8) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - CheckHeader(header); - - PngRabi rabi; - - if (setjmp(png_jmpbuf(rabi.png_))) - { - rabi.Destruct(); - throw OrthancException(ErrorCode_BadFileFormat); - } - - png_init_io(rabi.png_, f.fp_); - - Read(rabi); - } -#endif - - - namespace - { - struct MemoryBuffer - { - const uint8_t* buffer_; - size_t size_; - size_t pos_; - bool ok_; - }; - } - - - void PngReader::PngRabi::MemoryCallback(png_structp png_ptr, - png_bytep outBytes, - png_size_t byteCountToRead) - { - MemoryBuffer* from = reinterpret_cast(png_get_io_ptr(png_ptr)); - - if (!from->ok_) - { - return; - } - - if (from->pos_ + byteCountToRead > from->size_) - { - from->ok_ = false; - return; - } - - memcpy(outBytes, from->buffer_ + from->pos_, byteCountToRead); - - from->pos_ += byteCountToRead; - } - - - void PngReader::ReadFromMemory(const void* buffer, - size_t size) - { - if (size < 8) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - CheckHeader(buffer); - - PngRabi rabi; - - if (setjmp(png_jmpbuf(rabi.png_))) - { - rabi.Destruct(); - throw OrthancException(ErrorCode_BadFileFormat); - } - - MemoryBuffer tmp; - tmp.buffer_ = reinterpret_cast(buffer) + 8; // We skip the header - tmp.size_ = size - 8; - tmp.pos_ = 0; - tmp.ok_ = true; - - png_set_read_fn(rabi.png_, &tmp, PngRabi::MemoryCallback); - - Read(rabi); - - if (!tmp.ok_) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - void PngReader::ReadFromMemory(const std::string& buffer) - { - if (buffer.size() != 0) - { - ReadFromMemory(&buffer[0], buffer.size()); - } - else - { - ReadFromMemory(NULL, 0); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngReader.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_PNG) -# error The macro ORTHANC_ENABLE_PNG must be defined -#endif - -#if ORTHANC_ENABLE_PNG != 1 -# error PNG support must be enabled to include this file -#endif - -#include "ImageAccessor.h" - -#include "../Enumerations.h" - -#include -#include -#include - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -namespace Orthanc -{ - class PngReader : public ImageAccessor - { - private: - struct PngRabi; - - std::vector data_; - - void CheckHeader(const void* header); - - void Read(PngRabi& rabi); - - public: - PngReader(); - -#if ORTHANC_SANDBOXED == 0 - void ReadFromFile(const std::string& filename); -#endif - - void ReadFromMemory(const void* buffer, - size_t size); - - void ReadFromMemory(const std::string& buffer); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,274 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "PngWriter.h" - -#include -#include -#include -#include "../OrthancException.h" -#include "../ChunkedBuffer.h" -#include "../Toolbox.h" - -#if ORTHANC_SANDBOXED == 0 -# include "../SystemToolbox.h" -#endif - - -// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4 -// http://zarb.org/~gc/html/libpng.html -/* - void write_row_callback(png_ptr, png_uint_32 row, int pass) - { - }*/ - - - - -/* bool isError_; - -// http://www.libpng.org/pub/png/book/chapter14.html#png.ch14.div.2 - -static void ErrorHandler(png_structp png, png_const_charp message) -{ -printf("** [%s]\n", message); - -PngWriter* that = (PngWriter*) png_get_error_ptr(png); -that->isError_ = true; -printf("** %d\n", (int)that); - -//((PngWriter*) payload)->isError_ = true; -} - -static void WarningHandler(png_structp png, png_const_charp message) -{ - printf("++ %d\n", (int)message); -}*/ - - -namespace Orthanc -{ - struct PngWriter::PImpl - { - png_structp png_; - png_infop info_; - - // Filled by Prepare() - std::vector rows_; - int bitDepth_; - int colorType_; - }; - - - - PngWriter::PngWriter() : pimpl_(new PImpl) - { - pimpl_->png_ = NULL; - pimpl_->info_ = NULL; - - pimpl_->png_ = png_create_write_struct - (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); //this, ErrorHandler, WarningHandler); - if (!pimpl_->png_) - { - throw OrthancException(ErrorCode_NotEnoughMemory); - } - - pimpl_->info_ = png_create_info_struct(pimpl_->png_); - if (!pimpl_->info_) - { - png_destroy_write_struct(&pimpl_->png_, NULL); - throw OrthancException(ErrorCode_NotEnoughMemory); - } - } - - PngWriter::~PngWriter() - { - if (pimpl_->info_) - { - png_destroy_info_struct(pimpl_->png_, &pimpl_->info_); - } - - if (pimpl_->png_) - { - png_destroy_write_struct(&pimpl_->png_, NULL); - } - } - - - - void PngWriter::Prepare(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - pimpl_->rows_.resize(height); - for (unsigned int y = 0; y < height; y++) - { - pimpl_->rows_[y] = const_cast(reinterpret_cast(buffer)) + y * pitch; - } - - switch (format) - { - case PixelFormat_RGB24: - pimpl_->bitDepth_ = 8; - pimpl_->colorType_ = PNG_COLOR_TYPE_RGB; - break; - - case PixelFormat_RGBA32: - pimpl_->bitDepth_ = 8; - pimpl_->colorType_ = PNG_COLOR_TYPE_RGBA; - break; - - case PixelFormat_Grayscale8: - pimpl_->bitDepth_ = 8; - pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY; - break; - - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - pimpl_->bitDepth_ = 16; - pimpl_->colorType_ = PNG_COLOR_TYPE_GRAY; - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void PngWriter::Compress(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format) - { - png_set_IHDR(pimpl_->png_, pimpl_->info_, width, height, - pimpl_->bitDepth_, pimpl_->colorType_, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(pimpl_->png_, pimpl_->info_); - - if (height > 0) - { - switch (format) - { - case PixelFormat_Grayscale16: - case PixelFormat_SignedGrayscale16: - { - int transforms = 0; - if (Toolbox::DetectEndianness() == Endianness_Little) - { - transforms = PNG_TRANSFORM_SWAP_ENDIAN; - } - - png_set_rows(pimpl_->png_, pimpl_->info_, &pimpl_->rows_[0]); - png_write_png(pimpl_->png_, pimpl_->info_, transforms, NULL); - - break; - } - - default: - png_write_image(pimpl_->png_, &pimpl_->rows_[0]); - } - } - - png_write_end(pimpl_->png_, NULL); - } - - -#if ORTHANC_SANDBOXED == 0 - void PngWriter::WriteToFileInternal(const std::string& filename, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - Prepare(width, height, pitch, format, buffer); - - FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary); - if (!fp) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - png_init_io(pimpl_->png_, fp); - - if (setjmp(png_jmpbuf(pimpl_->png_))) - { - // Error during writing PNG - throw OrthancException(ErrorCode_CannotWriteFile); - } - - Compress(width, height, pitch, format); - - fclose(fp); - } -#endif - - - static void MemoryCallback(png_structp png_ptr, - png_bytep data, - png_size_t size) - { - ChunkedBuffer* buffer = reinterpret_cast(png_get_io_ptr(png_ptr)); - buffer->AddChunk(data, size); - } - - - - void PngWriter::WriteToMemoryInternal(std::string& png, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer) - { - ChunkedBuffer chunks; - - Prepare(width, height, pitch, format, buffer); - - if (setjmp(png_jmpbuf(pimpl_->png_))) - { - // Error during writing PNG - throw OrthancException(ErrorCode_InternalError); - } - - png_set_write_fn(pimpl_->png_, &chunks, MemoryCallback, NULL); - - Compress(width, height, pitch, format); - - chunks.Flatten(png); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Images/PngWriter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_PNG) -# error The macro ORTHANC_ENABLE_PNG must be defined -#endif - -#if ORTHANC_ENABLE_PNG != 1 -# error PNG support must be enabled to include this file -#endif - -#include "IImageWriter.h" - -#include - -namespace Orthanc -{ - class PngWriter : public IImageWriter - { - protected: -#if ORTHANC_SANDBOXED == 0 - virtual void WriteToFileInternal(const std::string& filename, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); -#endif - - virtual void WriteToMemoryInternal(std::string& png, - unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - - private: - struct PImpl; - boost::shared_ptr pimpl_; - - void Compress(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format); - - void Prepare(unsigned int width, - unsigned int height, - unsigned int pitch, - PixelFormat format, - const void* buffer); - - public: - PngWriter(); - - ~PngWriter(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "GenericJobUnserializer.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../SerializationToolbox.h" - -#include "Operations/LogJobOperation.h" -#include "Operations/NullOperationValue.h" -#include "Operations/SequenceOfOperationsJob.h" -#include "Operations/StringOperationValue.h" - -namespace Orthanc -{ - IJob* GenericJobUnserializer::UnserializeJob(const Json::Value& source) - { - const std::string type = SerializationToolbox::ReadString(source, "Type"); - - if (type == "SequenceOfOperations") - { - return new SequenceOfOperationsJob(*this, source); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot unserialize job of type: " + type); - } - } - - - IJobOperation* GenericJobUnserializer::UnserializeOperation(const Json::Value& source) - { - const std::string type = SerializationToolbox::ReadString(source, "Type"); - - if (type == "Log") - { - return new LogJobOperation; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot unserialize operation of type: " + type); - } - } - - - JobOperationValue* GenericJobUnserializer::UnserializeValue(const Json::Value& source) - { - const std::string type = SerializationToolbox::ReadString(source, "Type"); - - if (type == "String") - { - return new StringOperationValue(SerializationToolbox::ReadString(source, "Content")); - } - else if (type == "Null") - { - return new NullOperationValue; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Cannot unserialize value of type: " + type); - } - } -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/GenericJobUnserializer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IJobUnserializer.h" - -namespace Orthanc -{ - class GenericJobUnserializer : public IJobUnserializer - { - public: - virtual IJob* UnserializeJob(const Json::Value& value); - - virtual IJobOperation* UnserializeOperation(const Json::Value& value); - - virtual JobOperationValue* UnserializeValue(const Json::Value& value); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobStepResult.h" - -#include -#include - -namespace Orthanc -{ - class IJob : public boost::noncopyable - { - public: - virtual ~IJob() - { - } - - // Method called once the job enters the jobs engine - virtual void Start() = 0; - - virtual JobStepResult Step(const std::string& jobId) = 0; - - // Method called once the job is resubmitted after a failure - virtual void Reset() = 0; - - // For pausing/canceling/ending jobs: This method must release allocated resources - virtual void Stop(JobStopReason reason) = 0; - - virtual float GetProgress() = 0; - - virtual void GetJobType(std::string& target) = 0; - - virtual void GetPublicContent(Json::Value& value) = 0; - - virtual bool Serialize(Json::Value& value) = 0; - - // This function can only be called if the job has reached its - // "success" state - virtual bool GetOutput(std::string& output, - MimeType& mime, - const std::string& key) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJobUnserializer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJobUnserializer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJobUnserializer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/IJobUnserializer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IJob.h" -#include "Operations/JobOperationValue.h" -#include "Operations/IJobOperation.h" - -#include - -namespace Orthanc -{ - class IJobUnserializer : public boost::noncopyable - { - public: - virtual ~IJobUnserializer() - { - } - - virtual IJob* UnserializeJob(const Json::Value& value) = 0; - - virtual IJobOperation* UnserializeOperation(const Json::Value& value) = 0; - - virtual JobOperationValue* UnserializeValue(const Json::Value& value) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" - -#ifdef __EMSCRIPTEN__ -/* -Avoid this error: - -.../boost/math/special_functions/round.hpp:118:12: warning: implicit conversion from 'std::__2::numeric_limits::type' (aka 'long long') to 'float' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-int-float-conversion] -.../boost/math/special_functions/round.hpp:125:11: note: in instantiation of function template specialization 'boost::math::llround >' requested here -.../orthanc/Core/JobsEngine/JobInfo.cpp:69:44: note: in instantiation of function template specialization 'boost::math::llround' requested here - -.../boost/math/special_functions/round.hpp:86:12: warning: implicit conversion from 'std::__2::numeric_limits::type' (aka 'int') to 'float' changes value from 2147483647 to 2147483648 [-Wimplicit-int-float-conversion] -.../boost/math/special_functions/round.hpp:93:11: note: in instantiation of function template specialization 'boost::math::iround >' requested here -.../orthanc/Core/JobsEngine/JobInfo.cpp:133:39: note: in instantiation of function template specialization 'boost::math::iround' requested here -*/ -#pragma GCC diagnostic ignored "-Wimplicit-int-float-conversion" -#endif - -#include "JobInfo.h" - -#include "../OrthancException.h" - -// This "include" is mandatory for Release builds using Linux Standard Base -#include - -namespace Orthanc -{ - JobInfo::JobInfo(const std::string& id, - int priority, - JobState state, - const JobStatus& status, - const boost::posix_time::ptime& creationTime, - const boost::posix_time::ptime& lastStateChangeTime, - const boost::posix_time::time_duration& runtime) : - id_(id), - priority_(priority), - state_(state), - timestamp_(boost::posix_time::microsec_clock::universal_time()), - creationTime_(creationTime), - lastStateChangeTime_(lastStateChangeTime), - runtime_(runtime), - hasEta_(false), - status_(status) - { - if (state_ == JobState_Running) - { - float ms = static_cast(runtime_.total_milliseconds()); - - if (status_.GetProgress() > 0.01f && - ms > 0.01f) - { - float ratio = static_cast(1.0 - status_.GetProgress()); - long long remaining = boost::math::llround(ratio * ms); - eta_ = timestamp_ + boost::posix_time::milliseconds(remaining); - hasEta_ = true; - } - } - } - - - JobInfo::JobInfo() : - priority_(0), - state_(JobState_Failure), - timestamp_(boost::posix_time::microsec_clock::universal_time()), - creationTime_(timestamp_), - lastStateChangeTime_(timestamp_), - runtime_(boost::posix_time::milliseconds(0)), - hasEta_(false) - { - } - - - bool JobInfo::HasCompletionTime() const - { - return (state_ == JobState_Success || - state_ == JobState_Failure); - } - - - const boost::posix_time::ptime& JobInfo::GetEstimatedTimeOfArrival() const - { - if (hasEta_) - { - return eta_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - const boost::posix_time::ptime& JobInfo::GetCompletionTime() const - { - if (HasCompletionTime()) - { - return lastStateChangeTime_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void JobInfo::Format(Json::Value& target) const - { - target = Json::objectValue; - target["ID"] = id_; - target["Priority"] = priority_; - target["ErrorCode"] = static_cast(status_.GetErrorCode()); - target["ErrorDescription"] = EnumerationToString(status_.GetErrorCode()); - target["State"] = EnumerationToString(state_); - target["Timestamp"] = boost::posix_time::to_iso_string(timestamp_); - target["CreationTime"] = boost::posix_time::to_iso_string(creationTime_); - target["EffectiveRuntime"] = static_cast(runtime_.total_milliseconds()) / 1000.0; - target["Progress"] = boost::math::iround(status_.GetProgress() * 100.0f); - - target["Type"] = status_.GetJobType(); - target["Content"] = status_.GetPublicContent(); - - if (HasEstimatedTimeOfArrival()) - { - target["EstimatedTimeOfArrival"] = boost::posix_time::to_iso_string(GetEstimatedTimeOfArrival()); - } - - if (HasCompletionTime()) - { - target["CompletionTime"] = boost::posix_time::to_iso_string(GetCompletionTime()); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobInfo.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobStatus.h" - -#include - -namespace Orthanc -{ - class JobInfo - { - private: - std::string id_; - int priority_; - JobState state_; - boost::posix_time::ptime timestamp_; - boost::posix_time::ptime creationTime_; - boost::posix_time::ptime lastStateChangeTime_; - boost::posix_time::time_duration runtime_; - bool hasEta_; - boost::posix_time::ptime eta_; - JobStatus status_; - - public: - JobInfo(const std::string& id, - int priority, - JobState state, - const JobStatus& status, - const boost::posix_time::ptime& creationTime, - const boost::posix_time::ptime& lastStateChangeTime, - const boost::posix_time::time_duration& runtime); - - JobInfo(); - - const std::string& GetIdentifier() const - { - return id_; - } - - int GetPriority() const - { - return priority_; - } - - JobState GetState() const - { - return state_; - } - - const boost::posix_time::ptime& GetInfoTime() const - { - return timestamp_; - } - - const boost::posix_time::ptime& GetCreationTime() const - { - return creationTime_; - } - - const boost::posix_time::time_duration& GetRuntime() const - { - return runtime_; - } - - bool HasEstimatedTimeOfArrival() const - { - return hasEta_; - } - - bool HasCompletionTime() const; - - const boost::posix_time::ptime& GetEstimatedTimeOfArrival() const; - - const boost::posix_time::ptime& GetCompletionTime() const; - - const JobStatus& GetStatus() const - { - return status_; - } - - JobStatus& GetStatus() - { - return status_; - } - - void Format(Json::Value& target) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,326 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JobsEngine.h" - -#include "../Logging.h" -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - bool JobsEngine::IsRunning() - { - boost::mutex::scoped_lock lock(stateMutex_); - return (state_ == State_Running); - } - - - bool JobsEngine::ExecuteStep(JobsRegistry::RunningJob& running, - size_t workerIndex) - { - assert(running.IsValid()); - - if (running.IsPauseScheduled()) - { - running.GetJob().Stop(JobStopReason_Paused); - running.MarkPause(); - return false; - } - - if (running.IsCancelScheduled()) - { - running.GetJob().Stop(JobStopReason_Canceled); - running.MarkCanceled(); - return false; - } - - JobStepResult result; - - try - { - result = running.GetJob().Step(running.GetId()); - } - catch (OrthancException& e) - { - result = JobStepResult::Failure(e); - } - catch (boost::bad_lexical_cast&) - { - result = JobStepResult::Failure(ErrorCode_BadFileFormat, NULL); - } - catch (...) - { - result = JobStepResult::Failure(ErrorCode_InternalError, NULL); - } - - switch (result.GetCode()) - { - case JobStepCode_Success: - running.GetJob().Stop(JobStopReason_Success); - running.UpdateStatus(ErrorCode_Success, ""); - running.MarkSuccess(); - return false; - - case JobStepCode_Failure: - running.GetJob().Stop(JobStopReason_Failure); - running.UpdateStatus(result.GetFailureCode(), result.GetFailureDetails()); - running.MarkFailure(); - return false; - - case JobStepCode_Retry: - running.GetJob().Stop(JobStopReason_Retry); - running.UpdateStatus(ErrorCode_Success, ""); - running.MarkRetry(result.GetRetryTimeout()); - return false; - - case JobStepCode_Continue: - running.UpdateStatus(ErrorCode_Success, ""); - return true; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - void JobsEngine::RetryHandler(JobsEngine* engine) - { - assert(engine != NULL); - - while (engine->IsRunning()) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(engine->threadSleep_)); - engine->GetRegistry().ScheduleRetries(); - } - } - - - void JobsEngine::Worker(JobsEngine* engine, - size_t workerIndex) - { - assert(engine != NULL); - - LOG(INFO) << "Worker thread " << workerIndex << " has started"; - - while (engine->IsRunning()) - { - JobsRegistry::RunningJob running(engine->GetRegistry(), engine->threadSleep_); - - if (running.IsValid()) - { - LOG(INFO) << "Executing job with priority " << running.GetPriority() - << " in worker thread " << workerIndex << ": " << running.GetId(); - - while (engine->IsRunning()) - { - if (!engine->ExecuteStep(running, workerIndex)) - { - break; - } - } - } - } - } - - - JobsEngine::JobsEngine(size_t maxCompletedJobs) : - state_(State_Setup), - registry_(new JobsRegistry(maxCompletedJobs)), - threadSleep_(200), - workers_(1) - { - } - - - JobsEngine::~JobsEngine() - { - if (state_ != State_Setup && - state_ != State_Done) - { - LOG(ERROR) << "INTERNAL ERROR: JobsEngine::Stop() should be invoked manually to avoid mess in the destruction order!"; - Stop(); - } - } - - - JobsRegistry& JobsEngine::GetRegistry() - { - if (registry_.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - return *registry_; - } - - - void JobsEngine::LoadRegistryFromJson(IJobUnserializer& unserializer, - const Json::Value& serialized) - { - boost::mutex::scoped_lock lock(stateMutex_); - - if (state_ != State_Setup) - { - // Can only be invoked before calling "Start()" - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - assert(registry_.get() != NULL); - const size_t maxCompletedJobs = registry_->GetMaxCompletedJobs(); - registry_.reset(new JobsRegistry(unserializer, serialized, maxCompletedJobs)); - } - - - void JobsEngine::LoadRegistryFromString(IJobUnserializer& unserializer, - const std::string& serialized) - { - Json::Value value; - Json::Reader reader; - if (reader.parse(serialized, value)) - { - LoadRegistryFromJson(unserializer, value); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - void JobsEngine::SetWorkersCount(size_t count) - { - boost::mutex::scoped_lock lock(stateMutex_); - - if (state_ != State_Setup) - { - // Can only be invoked before calling "Start()" - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - workers_.resize(count); - } - - - void JobsEngine::SetThreadSleep(unsigned int sleep) - { - boost::mutex::scoped_lock lock(stateMutex_); - - if (state_ != State_Setup) - { - // Can only be invoked before calling "Start()" - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - threadSleep_ = sleep; - } - - - void JobsEngine::Start() - { - boost::mutex::scoped_lock lock(stateMutex_); - - if (state_ != State_Setup) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - retryHandler_ = boost::thread(RetryHandler, this); - - if (workers_.size() == 0) - { - // Use all the available CPUs - size_t n = boost::thread::hardware_concurrency(); - - if (n == 0) - { - n = 1; - } - - workers_.resize(n); - } - - for (size_t i = 0; i < workers_.size(); i++) - { - assert(workers_[i] == NULL); - workers_[i] = new boost::thread(Worker, this, i); - } - - state_ = State_Running; - - LOG(WARNING) << "The jobs engine has started with " << workers_.size() << " threads"; - } - - - void JobsEngine::Stop() - { - { - boost::mutex::scoped_lock lock(stateMutex_); - - if (state_ != State_Running) - { - return; - } - - state_ = State_Stopping; - } - - LOG(INFO) << "Stopping the jobs engine"; - - if (retryHandler_.joinable()) - { - retryHandler_.join(); - } - - for (size_t i = 0; i < workers_.size(); i++) - { - assert(workers_[i] != NULL); - - if (workers_[i]->joinable()) - { - workers_[i]->join(); - } - - delete workers_[i]; - } - - { - boost::mutex::scoped_lock lock(stateMutex_); - state_ = State_Done; - } - - LOG(WARNING) << "The jobs engine has stopped"; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsEngine.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobsRegistry.h" - -#include "../Compatibility.h" - -#include - -namespace Orthanc -{ - class JobsEngine : public boost::noncopyable - { - private: - enum State - { - State_Setup, - State_Running, - State_Stopping, - State_Done - }; - - boost::mutex stateMutex_; - State state_; - std::unique_ptr registry_; - boost::thread retryHandler_; - unsigned int threadSleep_; - std::vector workers_; - - bool IsRunning(); - - bool ExecuteStep(JobsRegistry::RunningJob& running, - size_t workerIndex); - - static void RetryHandler(JobsEngine* engine); - - static void Worker(JobsEngine* engine, - size_t workerIndex); - - public: - JobsEngine(size_t maxCompletedJobs); - - ~JobsEngine(); - - JobsRegistry& GetRegistry(); - - void LoadRegistryFromJson(IJobUnserializer& unserializer, - const Json::Value& serialized); - - void LoadRegistryFromString(IJobUnserializer& unserializer, - const std::string& serialized); - - void SetWorkersCount(size_t count); - - void SetThreadSleep(unsigned int sleep); - - void Start(); - - void Stop(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1474 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JobsRegistry.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" -#include "../SerializationToolbox.h" - -namespace Orthanc -{ - static const char* STATE = "State"; - static const char* TYPE = "Type"; - static const char* PRIORITY = "Priority"; - static const char* JOB = "Job"; - static const char* JOBS = "Jobs"; - static const char* JOBS_REGISTRY = "JobsRegistry"; - static const char* CREATION_TIME = "CreationTime"; - static const char* LAST_CHANGE_TIME = "LastChangeTime"; - static const char* RUNTIME = "Runtime"; - - - class JobsRegistry::JobHandler : public boost::noncopyable - { - private: - std::string id_; - JobState state_; - std::string jobType_; - std::unique_ptr job_; - int priority_; // "+inf()" means highest priority - boost::posix_time::ptime creationTime_; - boost::posix_time::ptime lastStateChangeTime_; - boost::posix_time::time_duration runtime_; - boost::posix_time::ptime retryTime_; - bool pauseScheduled_; - bool cancelScheduled_; - JobStatus lastStatus_; - - void Touch() - { - const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); - - if (state_ == JobState_Running) - { - runtime_ += (now - lastStateChangeTime_); - } - - lastStateChangeTime_ = now; - } - - void SetStateInternal(JobState state) - { - state_ = state; - pauseScheduled_ = false; - cancelScheduled_ = false; - Touch(); - } - - public: - JobHandler(IJob* job, - int priority) : - id_(Toolbox::GenerateUuid()), - state_(JobState_Pending), - job_(job), - priority_(priority), - creationTime_(boost::posix_time::microsec_clock::universal_time()), - lastStateChangeTime_(creationTime_), - runtime_(boost::posix_time::milliseconds(0)), - retryTime_(creationTime_), - pauseScheduled_(false), - cancelScheduled_(false) - { - if (job == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - job->GetJobType(jobType_); - job->Start(); - - lastStatus_ = JobStatus(ErrorCode_Success, "", *job_); - } - - const std::string& GetId() const - { - return id_; - } - - IJob& GetJob() const - { - assert(job_.get() != NULL); - return *job_; - } - - void SetPriority(int priority) - { - priority_ = priority; - } - - int GetPriority() const - { - return priority_; - } - - JobState GetState() const - { - return state_; - } - - void SetState(JobState state) - { - if (state == JobState_Retry) - { - // Use "SetRetryState()" - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - SetStateInternal(state); - } - } - - void SetRetryState(unsigned int timeout) - { - if (state_ == JobState_Running) - { - SetStateInternal(JobState_Retry); - retryTime_ = (boost::posix_time::microsec_clock::universal_time() + - boost::posix_time::milliseconds(timeout)); - } - else - { - // Only valid for running jobs - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - void SchedulePause() - { - if (state_ == JobState_Running) - { - pauseScheduled_ = true; - } - else - { - // Only valid for running jobs - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - void ScheduleCancel() - { - if (state_ == JobState_Running) - { - cancelScheduled_ = true; - } - else - { - // Only valid for running jobs - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - bool IsPauseScheduled() - { - return pauseScheduled_; - } - - bool IsCancelScheduled() - { - return cancelScheduled_; - } - - bool IsRetryReady(const boost::posix_time::ptime& now) const - { - if (state_ != JobState_Retry) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return retryTime_ <= now; - } - } - - const boost::posix_time::ptime& GetCreationTime() const - { - return creationTime_; - } - - const boost::posix_time::ptime& GetLastStateChangeTime() const - { - return lastStateChangeTime_; - } - - void SetLastStateChangeTime(const boost::posix_time::ptime& time) - { - lastStateChangeTime_ = time; - } - - const boost::posix_time::time_duration& GetRuntime() const - { - return runtime_; - } - - const JobStatus& GetLastStatus() const - { - return lastStatus_; - } - - void SetLastStatus(const JobStatus& status) - { - lastStatus_ = status; - Touch(); - } - - void SetLastErrorCode(ErrorCode code) - { - lastStatus_.SetErrorCode(code); - } - - bool Serialize(Json::Value& target) const - { - target = Json::objectValue; - - bool ok; - - if (state_ == JobState_Running) - { - // WARNING: Cannot directly access the "job_" member, as long - // as a "RunningJob" instance is running. We do not use a - // mutex at the "JobHandler" level, as serialization would be - // blocked while a step in the job is running. Instead, we - // save a snapshot of the serialized job. (*) - - if (lastStatus_.HasSerialized()) - { - target[JOB] = lastStatus_.GetSerialized(); - ok = true; - } - else - { - ok = false; - } - } - else - { - ok = job_->Serialize(target[JOB]); - } - - if (ok) - { - target[STATE] = EnumerationToString(state_); - target[PRIORITY] = priority_; - target[CREATION_TIME] = boost::posix_time::to_iso_string(creationTime_); - target[LAST_CHANGE_TIME] = boost::posix_time::to_iso_string(lastStateChangeTime_); - target[RUNTIME] = static_cast(runtime_.total_milliseconds()); - return true; - } - else - { - VLOG(1) << "Job backup is not supported for job of type: " << jobType_; - return false; - } - } - - JobHandler(IJobUnserializer& unserializer, - const Json::Value& serialized, - const std::string& id) : - id_(id), - pauseScheduled_(false), - cancelScheduled_(false) - { - state_ = StringToJobState(SerializationToolbox::ReadString(serialized, STATE)); - priority_ = SerializationToolbox::ReadInteger(serialized, PRIORITY); - creationTime_ = boost::posix_time::from_iso_string - (SerializationToolbox::ReadString(serialized, CREATION_TIME)); - lastStateChangeTime_ = boost::posix_time::from_iso_string - (SerializationToolbox::ReadString(serialized, LAST_CHANGE_TIME)); - runtime_ = boost::posix_time::milliseconds - (SerializationToolbox::ReadInteger(serialized, RUNTIME)); - - retryTime_ = creationTime_; - - job_.reset(unserializer.UnserializeJob(serialized[JOB])); - job_->GetJobType(jobType_); - job_->Start(); - - lastStatus_ = JobStatus(ErrorCode_Success, "", *job_); - } - }; - - - bool JobsRegistry::PriorityComparator::operator() (JobHandler*& a, - JobHandler*& b) const - { - return a->GetPriority() < b->GetPriority(); - } - - -#if defined(NDEBUG) - void JobsRegistry::CheckInvariants() const - { - } - -#else - bool JobsRegistry::IsPendingJob(const JobHandler& job) const - { - PendingJobs copy = pendingJobs_; - while (!copy.empty()) - { - if (copy.top() == &job) - { - return true; - } - - copy.pop(); - } - - return false; - } - - bool JobsRegistry::IsCompletedJob(JobHandler& job) const - { - for (CompletedJobs::const_iterator it = completedJobs_.begin(); - it != completedJobs_.end(); ++it) - { - if (*it == &job) - { - return true; - } - } - - return false; - } - - bool JobsRegistry::IsRetryJob(JobHandler& job) const - { - return retryJobs_.find(&job) != retryJobs_.end(); - } - - void JobsRegistry::CheckInvariants() const - { - { - PendingJobs copy = pendingJobs_; - while (!copy.empty()) - { - assert(copy.top()->GetState() == JobState_Pending); - copy.pop(); - } - } - - assert(completedJobs_.size() <= maxCompletedJobs_); - - for (CompletedJobs::const_iterator it = completedJobs_.begin(); - it != completedJobs_.end(); ++it) - { - assert((*it)->GetState() == JobState_Success || - (*it)->GetState() == JobState_Failure); - } - - for (RetryJobs::const_iterator it = retryJobs_.begin(); - it != retryJobs_.end(); ++it) - { - assert((*it)->GetState() == JobState_Retry); - } - - for (JobsIndex::const_iterator it = jobsIndex_.begin(); - it != jobsIndex_.end(); ++it) - { - JobHandler& job = *it->second; - - assert(job.GetId() == it->first); - - switch (job.GetState()) - { - case JobState_Pending: - assert(!IsRetryJob(job) && IsPendingJob(job) && !IsCompletedJob(job)); - break; - - case JobState_Success: - case JobState_Failure: - assert(!IsRetryJob(job) && !IsPendingJob(job) && IsCompletedJob(job)); - break; - - case JobState_Retry: - assert(IsRetryJob(job) && !IsPendingJob(job) && !IsCompletedJob(job)); - break; - - case JobState_Running: - case JobState_Paused: - assert(!IsRetryJob(job) && !IsPendingJob(job) && !IsCompletedJob(job)); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - } -#endif - - - void JobsRegistry::ForgetOldCompletedJobs() - { - while (completedJobs_.size() > maxCompletedJobs_) - { - assert(completedJobs_.front() != NULL); - - std::string id = completedJobs_.front()->GetId(); - assert(jobsIndex_.find(id) != jobsIndex_.end()); - - jobsIndex_.erase(id); - delete(completedJobs_.front()); - completedJobs_.pop_front(); - } - - CheckInvariants(); - } - - - void JobsRegistry::SetCompletedJob(JobHandler& job, - bool success) - { - job.SetState(success ? JobState_Success : JobState_Failure); - - completedJobs_.push_back(&job); - someJobComplete_.notify_all(); - } - - - void JobsRegistry::MarkRunningAsCompleted(JobHandler& job, - CompletedReason reason) - { - const char* tmp; - - switch (reason) - { - case CompletedReason_Success: - tmp = "success"; - break; - - case CompletedReason_Failure: - tmp = "failure"; - break; - - case CompletedReason_Canceled: - tmp = "cancel"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - LOG(INFO) << "Job has completed with " << tmp << ": " << job.GetId(); - - CheckInvariants(); - - assert(job.GetState() == JobState_Running); - SetCompletedJob(job, reason == CompletedReason_Success); - - if (reason == CompletedReason_Canceled) - { - job.SetLastErrorCode(ErrorCode_CanceledJob); - } - - if (observer_ != NULL) - { - if (reason == CompletedReason_Success) - { - observer_->SignalJobSuccess(job.GetId()); - } - else - { - observer_->SignalJobFailure(job.GetId()); - } - } - - // WARNING: The following call might make "job" invalid if the job - // history size is empty - ForgetOldCompletedJobs(); - } - - - void JobsRegistry::MarkRunningAsRetry(JobHandler& job, - unsigned int timeout) - { - LOG(INFO) << "Job scheduled for retry in " << timeout << "ms: " << job.GetId(); - - CheckInvariants(); - - assert(job.GetState() == JobState_Running && - retryJobs_.find(&job) == retryJobs_.end()); - - retryJobs_.insert(&job); - job.SetRetryState(timeout); - - CheckInvariants(); - } - - - void JobsRegistry::MarkRunningAsPaused(JobHandler& job) - { - LOG(INFO) << "Job paused: " << job.GetId(); - - CheckInvariants(); - assert(job.GetState() == JobState_Running); - - job.SetState(JobState_Paused); - - CheckInvariants(); - } - - - bool JobsRegistry::GetStateInternal(JobState& state, - const std::string& id) - { - CheckInvariants(); - - JobsIndex::const_iterator it = jobsIndex_.find(id); - if (it == jobsIndex_.end()) - { - return false; - } - else - { - state = it->second->GetState(); - return true; - } - } - - - JobsRegistry::~JobsRegistry() - { - for (JobsIndex::iterator it = jobsIndex_.begin(); it != jobsIndex_.end(); ++it) - { - assert(it->second != NULL); - delete it->second; - } - } - - - void JobsRegistry::SetMaxCompletedJobs(size_t n) - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - LOG(INFO) << "The size of the history of the jobs engine is set to: " << n << " job(s)"; - - maxCompletedJobs_ = n; - ForgetOldCompletedJobs(); - } - - - size_t JobsRegistry::GetMaxCompletedJobs() - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - return maxCompletedJobs_; - } - - - void JobsRegistry::ListJobs(std::set& target) - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - for (JobsIndex::const_iterator it = jobsIndex_.begin(); - it != jobsIndex_.end(); ++it) - { - target.insert(it->first); - } - } - - - bool JobsRegistry::GetJobInfo(JobInfo& target, - const std::string& id) - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::const_iterator found = jobsIndex_.find(id); - - if (found == jobsIndex_.end()) - { - return false; - } - else - { - const JobHandler& handler = *found->second; - target = JobInfo(handler.GetId(), - handler.GetPriority(), - handler.GetState(), - handler.GetLastStatus(), - handler.GetCreationTime(), - handler.GetLastStateChangeTime(), - handler.GetRuntime()); - return true; - } - } - - - bool JobsRegistry::GetJobOutput(std::string& output, - MimeType& mime, - const std::string& job, - const std::string& key) - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::const_iterator found = jobsIndex_.find(job); - - if (found == jobsIndex_.end()) - { - return false; - } - else - { - const JobHandler& handler = *found->second; - - if (handler.GetState() == JobState_Success) - { - return handler.GetJob().GetOutput(output, mime, key); - } - else - { - return false; - } - } - } - - - void JobsRegistry::SubmitInternal(std::string& id, - JobHandler* handler) - { - if (handler == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - std::unique_ptr protection(handler); - - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - id = handler->GetId(); - int priority = handler->GetPriority(); - - jobsIndex_.insert(std::make_pair(id, protection.release())); - - switch (handler->GetState()) - { - case JobState_Pending: - case JobState_Retry: - case JobState_Running: - handler->SetState(JobState_Pending); - pendingJobs_.push(handler); - pendingJobAvailable_.notify_one(); - break; - - case JobState_Success: - SetCompletedJob(*handler, true); - break; - - case JobState_Failure: - SetCompletedJob(*handler, false); - break; - - case JobState_Paused: - break; - - default: - { - std::string details = ("A job should not be loaded from state: " + - std::string(EnumerationToString(handler->GetState()))); - throw OrthancException(ErrorCode_InternalError, details); - } - } - - LOG(INFO) << "New job submitted with priority " << priority << ": " << id; - - if (observer_ != NULL) - { - observer_->SignalJobSubmitted(id); - } - - // WARNING: The following call might make "handler" invalid if - // the job history size is empty - ForgetOldCompletedJobs(); - } - } - - - void JobsRegistry::Submit(std::string& id, - IJob* job, // Takes ownership - int priority) - { - SubmitInternal(id, new JobHandler(job, priority)); - } - - - void JobsRegistry::Submit(IJob* job, // Takes ownership - int priority) - { - std::string id; - SubmitInternal(id, new JobHandler(job, priority)); - } - - - void JobsRegistry::SubmitAndWait(Json::Value& successContent, - IJob* job, // Takes ownership - int priority) - { - std::string id; - Submit(id, job, priority); - - JobState state = JobState_Pending; // Dummy initialization - - { - boost::mutex::scoped_lock lock(mutex_); - - for (;;) - { - if (!GetStateInternal(state, id)) - { - // Job has finished and has been lost (typically happens if - // "JobsHistorySize" is 0) - throw OrthancException(ErrorCode_InexistentItem, - "Cannot retrieve the status of the job, " - "make sure that \"JobsHistorySize\" is not 0"); - } - else if (state == JobState_Failure) - { - // Failure - JobsIndex::const_iterator it = jobsIndex_.find(id); - if (it != jobsIndex_.end()) // Should always be true, already tested in GetStateInternal() - { - ErrorCode code = it->second->GetLastStatus().GetErrorCode(); - const std::string& details = it->second->GetLastStatus().GetDetails(); - - if (details.empty()) - { - throw OrthancException(code); - } - else - { - throw OrthancException(code, details); - } - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - else if (state == JobState_Success) - { - // Success, try and retrieve the status of the job - JobsIndex::const_iterator it = jobsIndex_.find(id); - if (it == jobsIndex_.end()) - { - // Should not happen - state = JobState_Failure; - } - else - { - const JobStatus& status = it->second->GetLastStatus(); - successContent = status.GetPublicContent(); - } - - return; - } - else - { - // This job has not finished yet, wait for new completion - someJobComplete_.wait(lock); - } - } - } - } - - - bool JobsRegistry::SetPriority(const std::string& id, - int priority) - { - LOG(INFO) << "Changing priority to " << priority << " for job: " << id; - - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::iterator found = jobsIndex_.find(id); - - if (found == jobsIndex_.end()) - { - LOG(WARNING) << "Unknown job: " << id; - return false; - } - else - { - found->second->SetPriority(priority); - - if (found->second->GetState() == JobState_Pending) - { - // If the job is pending, we need to reconstruct the - // priority queue, as the heap condition has changed - - PendingJobs copy; - std::swap(copy, pendingJobs_); - - assert(pendingJobs_.empty()); - while (!copy.empty()) - { - pendingJobs_.push(copy.top()); - copy.pop(); - } - } - - CheckInvariants(); - return true; - } - } - - - void JobsRegistry::RemovePendingJob(const std::string& id) - { - // If the job is pending, we need to reconstruct the priority - // queue to remove it - PendingJobs copy; - std::swap(copy, pendingJobs_); - - assert(pendingJobs_.empty()); - while (!copy.empty()) - { - if (copy.top()->GetId() != id) - { - pendingJobs_.push(copy.top()); - } - - copy.pop(); - } - } - - - void JobsRegistry::RemoveRetryJob(JobHandler* handler) - { - RetryJobs::iterator item = retryJobs_.find(handler); - assert(item != retryJobs_.end()); - retryJobs_.erase(item); - } - - - bool JobsRegistry::Pause(const std::string& id) - { - LOG(INFO) << "Pausing job: " << id; - - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::iterator found = jobsIndex_.find(id); - - if (found == jobsIndex_.end()) - { - LOG(WARNING) << "Unknown job: " << id; - return false; - } - else - { - switch (found->second->GetState()) - { - case JobState_Pending: - RemovePendingJob(id); - found->second->SetState(JobState_Paused); - break; - - case JobState_Retry: - RemoveRetryJob(found->second); - found->second->SetState(JobState_Paused); - break; - - case JobState_Paused: - case JobState_Success: - case JobState_Failure: - // Nothing to be done - break; - - case JobState_Running: - found->second->SchedulePause(); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - CheckInvariants(); - return true; - } - } - - - bool JobsRegistry::Cancel(const std::string& id) - { - LOG(INFO) << "Canceling job: " << id; - - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::iterator found = jobsIndex_.find(id); - - if (found == jobsIndex_.end()) - { - LOG(WARNING) << "Unknown job: " << id; - return false; - } - else - { - switch (found->second->GetState()) - { - case JobState_Pending: - RemovePendingJob(id); - SetCompletedJob(*found->second, false); - found->second->SetLastErrorCode(ErrorCode_CanceledJob); - break; - - case JobState_Retry: - RemoveRetryJob(found->second); - SetCompletedJob(*found->second, false); - found->second->SetLastErrorCode(ErrorCode_CanceledJob); - break; - - case JobState_Paused: - SetCompletedJob(*found->second, false); - found->second->SetLastErrorCode(ErrorCode_CanceledJob); - break; - - case JobState_Success: - case JobState_Failure: - // Nothing to be done - break; - - case JobState_Running: - found->second->ScheduleCancel(); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - // WARNING: The following call might make "handler" invalid if - // the job history size is empty - ForgetOldCompletedJobs(); - - return true; - } - } - - - bool JobsRegistry::Resume(const std::string& id) - { - LOG(INFO) << "Resuming job: " << id; - - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::iterator found = jobsIndex_.find(id); - - if (found == jobsIndex_.end()) - { - LOG(WARNING) << "Unknown job: " << id; - return false; - } - else if (found->second->GetState() != JobState_Paused) - { - LOG(WARNING) << "Cannot resume a job that is not paused: " << id; - return false; - } - else - { - found->second->SetState(JobState_Pending); - pendingJobs_.push(found->second); - pendingJobAvailable_.notify_one(); - CheckInvariants(); - return true; - } - } - - - bool JobsRegistry::Resubmit(const std::string& id) - { - LOG(INFO) << "Resubmitting failed job: " << id; - - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - JobsIndex::iterator found = jobsIndex_.find(id); - - if (found == jobsIndex_.end()) - { - LOG(WARNING) << "Unknown job: " << id; - return false; - } - else if (found->second->GetState() != JobState_Failure) - { - LOG(WARNING) << "Cannot resubmit a job that has not failed: " << id; - return false; - } - else - { - found->second->GetJob().Reset(); - - bool ok = false; - for (CompletedJobs::iterator it = completedJobs_.begin(); - it != completedJobs_.end(); ++it) - { - if (*it == found->second) - { - ok = true; - completedJobs_.erase(it); - break; - } - } - - assert(ok); - - found->second->SetState(JobState_Pending); - pendingJobs_.push(found->second); - pendingJobAvailable_.notify_one(); - - CheckInvariants(); - return true; - } - } - - - void JobsRegistry::ScheduleRetries() - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - RetryJobs copy; - std::swap(copy, retryJobs_); - - const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); - - assert(retryJobs_.empty()); - for (RetryJobs::iterator it = copy.begin(); it != copy.end(); ++it) - { - if ((*it)->IsRetryReady(now)) - { - LOG(INFO) << "Retrying job: " << (*it)->GetId(); - (*it)->SetState(JobState_Pending); - pendingJobs_.push(*it); - pendingJobAvailable_.notify_one(); - } - else - { - retryJobs_.insert(*it); - } - } - - CheckInvariants(); - } - - - bool JobsRegistry::GetState(JobState& state, - const std::string& id) - { - boost::mutex::scoped_lock lock(mutex_); - return GetStateInternal(state, id); - } - - - void JobsRegistry::SetObserver(JobsRegistry::IObserver& observer) - { - boost::mutex::scoped_lock lock(mutex_); - observer_ = &observer; - } - - - void JobsRegistry::ResetObserver() - { - boost::mutex::scoped_lock lock(mutex_); - observer_ = NULL; - } - - - JobsRegistry::RunningJob::RunningJob(JobsRegistry& registry, - unsigned int timeout) : - registry_(registry), - handler_(NULL), - targetState_(JobState_Failure), - targetRetryTimeout_(0), - canceled_(false) - { - { - boost::mutex::scoped_lock lock(registry_.mutex_); - - while (registry_.pendingJobs_.empty()) - { - if (timeout == 0) - { - registry_.pendingJobAvailable_.wait(lock); - } - else - { - bool success = registry_.pendingJobAvailable_.timed_wait - (lock, boost::posix_time::milliseconds(timeout)); - if (!success) - { - // No pending job - return; - } - } - } - - handler_ = registry_.pendingJobs_.top(); - registry_.pendingJobs_.pop(); - - assert(handler_->GetState() == JobState_Pending); - handler_->SetState(JobState_Running); - handler_->SetLastErrorCode(ErrorCode_Success); - - job_ = &handler_->GetJob(); - id_ = handler_->GetId(); - priority_ = handler_->GetPriority(); - } - } - - - JobsRegistry::RunningJob::~RunningJob() - { - if (IsValid()) - { - boost::mutex::scoped_lock lock(registry_.mutex_); - - switch (targetState_) - { - case JobState_Failure: - registry_.MarkRunningAsCompleted - (*handler_, canceled_ ? CompletedReason_Canceled : CompletedReason_Failure); - break; - - case JobState_Success: - registry_.MarkRunningAsCompleted(*handler_, CompletedReason_Success); - break; - - case JobState_Paused: - registry_.MarkRunningAsPaused(*handler_); - break; - - case JobState_Retry: - registry_.MarkRunningAsRetry(*handler_, targetRetryTimeout_); - break; - - default: - assert(0); - } - } - } - - - bool JobsRegistry::RunningJob::IsValid() const - { - return (handler_ != NULL && - job_ != NULL); - } - - - const std::string& JobsRegistry::RunningJob::GetId() const - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return id_; - } - } - - - int JobsRegistry::RunningJob::GetPriority() const - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return priority_; - } - } - - - IJob& JobsRegistry::RunningJob::GetJob() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return *job_; - } - } - - - bool JobsRegistry::RunningJob::IsPauseScheduled() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - boost::mutex::scoped_lock lock(registry_.mutex_); - registry_.CheckInvariants(); - assert(handler_->GetState() == JobState_Running); - - return handler_->IsPauseScheduled(); - } - } - - - bool JobsRegistry::RunningJob::IsCancelScheduled() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - boost::mutex::scoped_lock lock(registry_.mutex_); - registry_.CheckInvariants(); - assert(handler_->GetState() == JobState_Running); - - return handler_->IsCancelScheduled(); - } - } - - - void JobsRegistry::RunningJob::MarkSuccess() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - targetState_ = JobState_Success; - } - } - - - void JobsRegistry::RunningJob::MarkFailure() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - targetState_ = JobState_Failure; - } - } - - - void JobsRegistry::RunningJob::MarkCanceled() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - targetState_ = JobState_Failure; - canceled_ = true; - } - } - - - void JobsRegistry::RunningJob::MarkPause() - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - targetState_ = JobState_Paused; - } - } - - - void JobsRegistry::RunningJob::MarkRetry(unsigned int timeout) - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - targetState_ = JobState_Retry; - targetRetryTimeout_ = timeout; - } - } - - - void JobsRegistry::RunningJob::UpdateStatus(ErrorCode code, - const std::string& details) - { - if (!IsValid()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - JobStatus status(code, details, *job_); - - boost::mutex::scoped_lock lock(registry_.mutex_); - registry_.CheckInvariants(); - assert(handler_->GetState() == JobState_Running); - - handler_->SetLastStatus(status); - } - } - - - - void JobsRegistry::Serialize(Json::Value& target) - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - target = Json::objectValue; - target[TYPE] = JOBS_REGISTRY; - target[JOBS] = Json::objectValue; - - for (JobsIndex::const_iterator it = jobsIndex_.begin(); - it != jobsIndex_.end(); ++it) - { - Json::Value v; - if (it->second->Serialize(v)) - { - target[JOBS][it->first] = v; - } - } - } - - - JobsRegistry::JobsRegistry(IJobUnserializer& unserializer, - const Json::Value& s, - size_t maxCompletedJobs) : - maxCompletedJobs_(maxCompletedJobs), - observer_(NULL) - { - if (SerializationToolbox::ReadString(s, TYPE) != JOBS_REGISTRY || - !s.isMember(JOBS) || - s[JOBS].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value::Members members = s[JOBS].getMemberNames(); - - for (Json::Value::Members::const_iterator it = members.begin(); - it != members.end(); ++it) - { - std::unique_ptr job; - - try - { - job.reset(new JobHandler(unserializer, s[JOBS][*it], *it)); - } - catch (OrthancException& e) - { - LOG(WARNING) << "Cannot unserialize one job from previous execution, " - << "skipping it: " << e.What(); - continue; - } - - const boost::posix_time::ptime lastChangeTime = job->GetLastStateChangeTime(); - - std::string id; - SubmitInternal(id, job.release()); - - // Check whether the job has not been removed (which could be - // the case if the "maxCompletedJobs_" value gets smaller) - JobsIndex::iterator found = jobsIndex_.find(id); - if (found != jobsIndex_.end()) - { - // The job still lies in the history: Update the time of its - // last change to the time that was serialized - assert(found->second != NULL); - found->second->SetLastStateChangeTime(lastChangeTime); - } - } - } - - - void JobsRegistry::GetStatistics(unsigned int& pending, - unsigned int& running, - unsigned int& success, - unsigned int& failed) - { - boost::mutex::scoped_lock lock(mutex_); - CheckInvariants(); - - pending = 0; - running = 0; - success = 0; - failed = 0; - - for (JobsIndex::const_iterator it = jobsIndex_.begin(); - it != jobsIndex_.end(); ++it) - { - JobHandler& job = *it->second; - - switch (job.GetState()) - { - case JobState_Retry: - case JobState_Pending: - pending ++; - break; - - case JobState_Paused: - case JobState_Running: - running ++; - break; - - case JobState_Success: - success ++; - break; - - case JobState_Failure: - failed ++; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobsRegistry.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,255 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The job engine cannot be used in sandboxed environments -#endif - -#include "JobInfo.h" -#include "IJobUnserializer.h" - -#include -#include -#include -#include -#include - -namespace Orthanc -{ - // This class handles the state machine of the jobs engine - class JobsRegistry : public boost::noncopyable - { - public: - class IObserver : public boost::noncopyable - { - public: - virtual ~IObserver() - { - } - - virtual void SignalJobSubmitted(const std::string& jobId) = 0; - - virtual void SignalJobSuccess(const std::string& jobId) = 0; - - virtual void SignalJobFailure(const std::string& jobId) = 0; - }; - - private: - enum CompletedReason - { - CompletedReason_Success, - CompletedReason_Failure, - CompletedReason_Canceled - }; - - class JobHandler; - - struct PriorityComparator - { - bool operator() (JobHandler*& a, - JobHandler*& b) const; - }; - - typedef std::map JobsIndex; - typedef std::list CompletedJobs; - typedef std::set RetryJobs; - typedef std::priority_queue, // Could be a "std::deque" - PriorityComparator> PendingJobs; - - boost::mutex mutex_; - JobsIndex jobsIndex_; - PendingJobs pendingJobs_; - CompletedJobs completedJobs_; - RetryJobs retryJobs_; - - boost::condition_variable pendingJobAvailable_; - boost::condition_variable someJobComplete_; - size_t maxCompletedJobs_; - - IObserver* observer_; - - -#ifndef NDEBUG - bool IsPendingJob(const JobHandler& job) const; - - bool IsCompletedJob(JobHandler& job) const; - - bool IsRetryJob(JobHandler& job) const; -#endif - - void CheckInvariants() const; - - void ForgetOldCompletedJobs(); - - void SetCompletedJob(JobHandler& job, - bool success); - - void MarkRunningAsCompleted(JobHandler& job, - CompletedReason reason); - - void MarkRunningAsRetry(JobHandler& job, - unsigned int timeout); - - void MarkRunningAsPaused(JobHandler& job); - - bool GetStateInternal(JobState& state, - const std::string& id); - - void RemovePendingJob(const std::string& id); - - void RemoveRetryJob(JobHandler* handler); - - void SubmitInternal(std::string& id, - JobHandler* handler); - - public: - JobsRegistry(size_t maxCompletedJobs) : - maxCompletedJobs_(maxCompletedJobs), - observer_(NULL) - { - } - - JobsRegistry(IJobUnserializer& unserializer, - const Json::Value& s, - size_t maxCompletedJobs); - - ~JobsRegistry(); - - void SetMaxCompletedJobs(size_t i); - - size_t GetMaxCompletedJobs(); - - void ListJobs(std::set& target); - - bool GetJobInfo(JobInfo& target, - const std::string& id); - - bool GetJobOutput(std::string& output, - MimeType& mime, - const std::string& job, - const std::string& key); - - void Serialize(Json::Value& target); - - void Submit(std::string& id, - IJob* job, // Takes ownership - int priority); - - void Submit(IJob* job, // Takes ownership - int priority); - - void SubmitAndWait(Json::Value& successContent, - IJob* job, // Takes ownership - int priority); - - bool SetPriority(const std::string& id, - int priority); - - bool Pause(const std::string& id); - - bool Resume(const std::string& id); - - bool Resubmit(const std::string& id); - - bool Cancel(const std::string& id); - - void ScheduleRetries(); - - bool GetState(JobState& state, - const std::string& id); - - void SetObserver(IObserver& observer); - - void ResetObserver(); - - void GetStatistics(unsigned int& pending, - unsigned int& running, - unsigned int& success, - unsigned int& errors); - - class RunningJob : public boost::noncopyable - { - private: - JobsRegistry& registry_; - JobHandler* handler_; // Can only be accessed if the - // registry mutex is locked! - IJob* job_; // Will by design be in mutual exclusion, - // because only one RunningJob can be - // executed at a time on a JobHandler - - std::string id_; - int priority_; - JobState targetState_; - unsigned int targetRetryTimeout_; - bool canceled_; - - public: - RunningJob(JobsRegistry& registry, - unsigned int timeout); - - ~RunningJob(); - - bool IsValid() const; - - const std::string& GetId() const; - - int GetPriority() const; - - IJob& GetJob(); - - bool IsPauseScheduled(); - - bool IsCancelScheduled(); - - void MarkSuccess(); - - void MarkFailure(); - - void MarkPause(); - - void MarkCanceled(); - - void MarkRetry(unsigned int timeout); - - void UpdateStatus(ErrorCode code, - const std::string& details); - }; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JobStatus.h" - -#include "../OrthancException.h" - -namespace Orthanc -{ - JobStatus::JobStatus() : - errorCode_(ErrorCode_InternalError), - progress_(0), - jobType_("Invalid"), - publicContent_(Json::objectValue), - hasSerialized_(false) - { - } - - - JobStatus::JobStatus(ErrorCode code, - const std::string& details, - IJob& job) : - errorCode_(code), - progress_(job.GetProgress()), - publicContent_(Json::objectValue), - details_(details) - { - if (progress_ < 0) - { - progress_ = 0; - } - - if (progress_ > 1) - { - progress_ = 1; - } - - job.GetJobType(jobType_); - job.GetPublicContent(publicContent_); - - hasSerialized_ = job.Serialize(serialized_); - } - - - const Json::Value& JobStatus::GetSerialized() const - { - if (!hasSerialized_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return serialized_; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStatus.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IJob.h" - -namespace Orthanc -{ - class JobStatus - { - private: - ErrorCode errorCode_; - float progress_; - std::string jobType_; - Json::Value publicContent_; - Json::Value serialized_; - bool hasSerialized_; - std::string details_; - - public: - JobStatus(); - - JobStatus(ErrorCode code, - const std::string& details, - IJob& job); - - ErrorCode GetErrorCode() const - { - return errorCode_; - } - - void SetErrorCode(ErrorCode error) - { - errorCode_ = error; - } - - float GetProgress() const - { - return progress_; - } - - const std::string& GetJobType() const - { - return jobType_; - } - - const Json::Value& GetPublicContent() const - { - return publicContent_; - } - - const Json::Value& GetSerialized() const; - - bool HasSerialized() const - { - return hasSerialized_; - } - - const std::string& GetDetails() const - { - return details_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "JobStepResult.h" - -#include "../OrthancException.h" - -namespace Orthanc -{ - JobStepResult JobStepResult::Retry(unsigned int timeout) - { - JobStepResult result(JobStepCode_Retry); - result.timeout_ = timeout; - return result; - } - - - JobStepResult JobStepResult::Failure(const ErrorCode& error, - const char* details) - { - JobStepResult result(JobStepCode_Failure); - result.error_ = error; - - if (details != NULL) - { - result.failureDetails_ = details; - } - - return result; - } - - - JobStepResult JobStepResult::Failure(const OrthancException& exception) - { - return Failure(exception.GetErrorCode(), - exception.HasDetails() ? exception.GetDetails() : NULL); - } - - - unsigned int JobStepResult::GetRetryTimeout() const - { - if (code_ == JobStepCode_Retry) - { - return timeout_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - ErrorCode JobStepResult::GetFailureCode() const - { - if (code_ == JobStepCode_Failure) - { - return error_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - const std::string& JobStepResult::GetFailureDetails() const - { - if (code_ == JobStepCode_Failure) - { - return failureDetails_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/JobStepResult.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Enumerations.h" - -namespace Orthanc -{ - class OrthancException; - - class JobStepResult - { - private: - JobStepCode code_; - unsigned int timeout_; - ErrorCode error_; - std::string failureDetails_; - - explicit JobStepResult(JobStepCode code) : - code_(code), - timeout_(0), - error_(ErrorCode_Success) - { - } - - public: - explicit JobStepResult() : - code_(JobStepCode_Failure), - timeout_(0), - error_(ErrorCode_InternalError) - { - } - - static JobStepResult Success() - { - return JobStepResult(JobStepCode_Success); - } - - static JobStepResult Continue() - { - return JobStepResult(JobStepCode_Continue); - } - - static JobStepResult Retry(unsigned int timeout); - - static JobStepResult Failure(const ErrorCode& error, - const char* details); - - static JobStepResult Failure(const OrthancException& exception); - - JobStepCode GetCode() const - { - return code_; - } - - unsigned int GetRetryTimeout() const; - - ErrorCode GetFailureCode() const; - - const std::string& GetFailureDetails() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/IJobOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/IJobOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/IJobOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/IJobOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobOperationValues.h" - -namespace Orthanc -{ - class IJobOperation : public boost::noncopyable - { - public: - virtual ~IJobOperation() - { - } - - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input) = 0; - - virtual void Serialize(Json::Value& result) const = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValue.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValue.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValue.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include - -namespace Orthanc -{ - class JobOperationValue : public boost::noncopyable - { - public: - enum Type - { - Type_DicomInstance, - Type_Null, - Type_String - }; - - private: - Type type_; - - protected: - JobOperationValue(Type type) : - type_(type) - { - } - - public: - virtual ~JobOperationValue() - { - } - - Type GetType() const - { - return type_; - } - - virtual JobOperationValue* Clone() const = 0; - - virtual void Serialize(Json::Value& target) const = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeaders.h" -#include "JobOperationValues.h" - -#include "../IJobUnserializer.h" -#include "../../OrthancException.h" - -#include -#include - -namespace Orthanc -{ - void JobOperationValues::Append(JobOperationValues& target, - bool clear) - { - target.Reserve(target.GetSize() + GetSize()); - - for (size_t i = 0; i < values_.size(); i++) - { - if (clear) - { - target.Append(values_[i]); - values_[i] = NULL; - } - else - { - target.Append(GetValue(i).Clone()); - } - } - - if (clear) - { - Clear(); - } - } - - - void JobOperationValues::Clear() - { - for (size_t i = 0; i < values_.size(); i++) - { - if (values_[i] != NULL) - { - delete values_[i]; - } - } - - values_.clear(); - } - - - void JobOperationValues::Append(JobOperationValue* value) // Takes ownership - { - if (value == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else - { - values_.push_back(value); - } - } - - - JobOperationValue& JobOperationValues::GetValue(size_t index) const - { - if (index >= values_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - assert(values_[index] != NULL); - return *values_[index]; - } - } - - - void JobOperationValues::Serialize(Json::Value& target) const - { - target = Json::arrayValue; - - for (size_t i = 0; i < values_.size(); i++) - { - Json::Value tmp; - values_[i]->Serialize(tmp); - target.append(tmp); - } - } - - - JobOperationValues* JobOperationValues::Unserialize(IJobUnserializer& unserializer, - const Json::Value& source) - { - if (source.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - std::unique_ptr result(new JobOperationValues); - - result->Reserve(source.size()); - - for (Json::Value::ArrayIndex i = 0; i < source.size(); i++) - { - result->Append(unserializer.UnserializeValue(source[i])); - } - - return result.release(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/JobOperationValues.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobOperationValue.h" - -#include - -namespace Orthanc -{ - class IJobUnserializer; - - class JobOperationValues : public boost::noncopyable - { - private: - std::vector values_; - - void Append(JobOperationValues& target, - bool clear); - - public: - ~JobOperationValues() - { - Clear(); - } - - void Move(JobOperationValues& target) - { - return Append(target, true); - } - - void Copy(JobOperationValues& target) - { - return Append(target, false); - } - - void Clear(); - - void Reserve(size_t count) - { - values_.reserve(count); - } - - void Append(JobOperationValue* value); // Takes ownership - - size_t GetSize() const - { - return values_.size(); - } - - JobOperationValue& GetValue(size_t index) const; - - void Serialize(Json::Value& target) const; - - static JobOperationValues* Unserialize(IJobUnserializer& unserializer, - const Json::Value& source); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeaders.h" -#include "LogJobOperation.h" - -#include "../../Logging.h" -#include "StringOperationValue.h" - -namespace Orthanc -{ - void LogJobOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input) - { - switch (input.GetType()) - { - case JobOperationValue::Type_String: - LOG(INFO) << "Job value: " - << dynamic_cast(input).GetContent(); - break; - - case JobOperationValue::Type_Null: - LOG(INFO) << "Job value: (null)"; - break; - - default: - LOG(INFO) << "Job value: (unsupport)"; - break; - } - - outputs.Append(input.Clone()); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/LogJobOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IJobOperation.h" - -namespace Orthanc -{ - class LogJobOperation : public IJobOperation - { - public: - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input); - - virtual void Serialize(Json::Value& result) const - { - result = Json::objectValue; - result["Type"] = "Log"; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/NullOperationValue.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/NullOperationValue.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/NullOperationValue.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/NullOperationValue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobOperationValue.h" - -namespace Orthanc -{ - class NullOperationValue : public JobOperationValue - { - public: - NullOperationValue() : - JobOperationValue(Type_Null) - { - } - - virtual JobOperationValue* Clone() const - { - return new NullOperationValue; - } - - virtual void Serialize(Json::Value& target) const - { - target = Json::objectValue; - target["Type"] = "Null"; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,475 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeaders.h" -#include "SequenceOfOperationsJob.h" - -#include "../../Logging.h" -#include "../../OrthancException.h" -#include "../../SerializationToolbox.h" -#include "../IJobUnserializer.h" - -namespace Orthanc -{ - static const char* CURRENT = "Current"; - static const char* DESCRIPTION = "Description"; - static const char* NEXT_OPERATIONS = "Next"; - static const char* OPERATION = "Operation"; - static const char* OPERATIONS = "Operations"; - static const char* ORIGINAL_INPUTS = "OriginalInputs"; - static const char* TRAILING_TIMEOUT = "TrailingTimeout"; - static const char* TYPE = "Type"; - static const char* WORK_INPUTS = "WorkInputs"; - - - class SequenceOfOperationsJob::Operation : public boost::noncopyable - { - private: - size_t index_; - std::unique_ptr operation_; - std::unique_ptr originalInputs_; - std::unique_ptr workInputs_; - std::list nextOperations_; - size_t currentInput_; - - public: - Operation(size_t index, - IJobOperation* operation) : - index_(index), - operation_(operation), - originalInputs_(new JobOperationValues), - workInputs_(new JobOperationValues), - currentInput_(0) - { - if (operation == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - } - - void AddOriginalInput(const JobOperationValue& value) - { - if (currentInput_ != 0) - { - // Cannot add input after processing has started - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - originalInputs_->Append(value.Clone()); - } - } - - const JobOperationValues& GetOriginalInputs() const - { - return *originalInputs_; - } - - void Reset() - { - workInputs_->Clear(); - currentInput_ = 0; - } - - void AddNextOperation(Operation& other, - bool unserializing) - { - if (other.index_ <= index_) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (!unserializing && - currentInput_ != 0) - { - // Cannot add input after processing has started - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - nextOperations_.push_back(&other); - } - } - - bool IsDone() const - { - return currentInput_ >= originalInputs_->GetSize() + workInputs_->GetSize(); - } - - void Step() - { - if (IsDone()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - const JobOperationValue* input; - - if (currentInput_ < originalInputs_->GetSize()) - { - input = &originalInputs_->GetValue(currentInput_); - } - else - { - input = &workInputs_->GetValue(currentInput_ - originalInputs_->GetSize()); - } - - JobOperationValues outputs; - operation_->Apply(outputs, *input); - - if (!nextOperations_.empty()) - { - std::list::iterator first = nextOperations_.begin(); - outputs.Move(*(*first)->workInputs_); - - std::list::iterator current = first; - ++current; - - while (current != nextOperations_.end()) - { - (*first)->workInputs_->Copy(*(*current)->workInputs_); - ++current; - } - } - - currentInput_ += 1; - } - - void Serialize(Json::Value& target) const - { - target = Json::objectValue; - target[CURRENT] = static_cast(currentInput_); - operation_->Serialize(target[OPERATION]); - originalInputs_->Serialize(target[ORIGINAL_INPUTS]); - workInputs_->Serialize(target[WORK_INPUTS]); - - Json::Value tmp = Json::arrayValue; - for (std::list::const_iterator it = nextOperations_.begin(); - it != nextOperations_.end(); ++it) - { - tmp.append(static_cast((*it)->index_)); - } - - target[NEXT_OPERATIONS] = tmp; - } - - Operation(IJobUnserializer& unserializer, - Json::Value::ArrayIndex index, - const Json::Value& serialized) : - index_(index) - { - if (serialized.type() != Json::objectValue || - !serialized.isMember(OPERATION) || - !serialized.isMember(ORIGINAL_INPUTS) || - !serialized.isMember(WORK_INPUTS)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - currentInput_ = SerializationToolbox::ReadUnsignedInteger(serialized, CURRENT); - operation_.reset(unserializer.UnserializeOperation(serialized[OPERATION])); - originalInputs_.reset(JobOperationValues::Unserialize - (unserializer, serialized[ORIGINAL_INPUTS])); - workInputs_.reset(JobOperationValues::Unserialize - (unserializer, serialized[WORK_INPUTS])); - } - }; - - - SequenceOfOperationsJob::SequenceOfOperationsJob() : - done_(false), - current_(0), - trailingTimeout_(boost::posix_time::milliseconds(1000)) - { - } - - - SequenceOfOperationsJob::~SequenceOfOperationsJob() - { - for (size_t i = 0; i < operations_.size(); i++) - { - if (operations_[i] != NULL) - { - delete operations_[i]; - } - } - } - - - void SequenceOfOperationsJob::SetDescription(const std::string& description) - { - boost::mutex::scoped_lock lock(mutex_); - description_ = description; - } - - - void SequenceOfOperationsJob::GetDescription(std::string& description) - { - boost::mutex::scoped_lock lock(mutex_); - description = description_; - } - - - void SequenceOfOperationsJob::Register(IObserver& observer) - { - boost::mutex::scoped_lock lock(mutex_); - observers_.push_back(&observer); - } - - - void SequenceOfOperationsJob::Lock::SetTrailingOperationTimeout(unsigned int timeout) - { - that_.trailingTimeout_ = boost::posix_time::milliseconds(timeout); - } - - - size_t SequenceOfOperationsJob::Lock::AddOperation(IJobOperation* operation) - { - if (IsDone()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - size_t index = that_.operations_.size(); - - that_.operations_.push_back(new Operation(index, operation)); - that_.operationAdded_.notify_one(); - - return index; - } - - - void SequenceOfOperationsJob::Lock::AddInput(size_t index, - const JobOperationValue& value) - { - if (IsDone()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (index >= that_.operations_.size() || - index < that_.current_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - that_.operations_[index]->AddOriginalInput(value); - } - } - - - void SequenceOfOperationsJob::Lock::Connect(size_t input, - size_t output) - { - if (IsDone()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (input >= output || - input >= that_.operations_.size() || - output >= that_.operations_.size() || - input < that_.current_ || - output < that_.current_) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - Operation& a = *that_.operations_[input]; - Operation& b = *that_.operations_[output]; - a.AddNextOperation(b, false /* not unserializing */); - } - } - - - JobStepResult SequenceOfOperationsJob::Step(const std::string& jobId) - { - boost::mutex::scoped_lock lock(mutex_); - - if (current_ == operations_.size()) - { - LOG(INFO) << "Executing the trailing timeout in the sequence of operations"; - operationAdded_.timed_wait(lock, trailingTimeout_); - - if (current_ == operations_.size()) - { - // No operation was added during the trailing timeout: The - // job is over - LOG(INFO) << "The sequence of operations is over"; - done_ = true; - - for (std::list::iterator it = observers_.begin(); - it != observers_.end(); ++it) - { - (*it)->SignalDone(*this); - } - - return JobStepResult::Success(); - } - else - { - LOG(INFO) << "New operation were added to the sequence of operations"; - } - } - - assert(current_ < operations_.size()); - - while (current_ < operations_.size() && - operations_[current_]->IsDone()) - { - current_++; - } - - if (current_ < operations_.size()) - { - operations_[current_]->Step(); - } - - return JobStepResult::Continue(); - } - - - void SequenceOfOperationsJob::Reset() - { - boost::mutex::scoped_lock lock(mutex_); - - current_ = 0; - done_ = false; - - for (size_t i = 0; i < operations_.size(); i++) - { - operations_[i]->Reset(); - } - } - - - float SequenceOfOperationsJob::GetProgress() - { - boost::mutex::scoped_lock lock(mutex_); - - return (static_cast(current_) / - static_cast(operations_.size() + 1)); - } - - - void SequenceOfOperationsJob::GetPublicContent(Json::Value& value) - { - boost::mutex::scoped_lock lock(mutex_); - - value["CountOperations"] = static_cast(operations_.size()); - value["Description"] = description_; - } - - - bool SequenceOfOperationsJob::Serialize(Json::Value& value) - { - boost::mutex::scoped_lock lock(mutex_); - - value = Json::objectValue; - - std::string jobType; - GetJobType(jobType); - value[TYPE] = jobType; - - value[DESCRIPTION] = description_; - value[TRAILING_TIMEOUT] = static_cast(trailingTimeout_.total_milliseconds()); - value[CURRENT] = static_cast(current_); - - Json::Value tmp = Json::arrayValue; - for (size_t i = 0; i < operations_.size(); i++) - { - Json::Value operation = Json::objectValue; - operations_[i]->Serialize(operation); - tmp.append(operation); - } - - value[OPERATIONS] = tmp; - - return true; - } - - - SequenceOfOperationsJob::SequenceOfOperationsJob(IJobUnserializer& unserializer, - const Json::Value& serialized) : - done_(false) - { - std::string jobType; - GetJobType(jobType); - - if (SerializationToolbox::ReadString(serialized, TYPE) != jobType || - !serialized.isMember(OPERATIONS) || - serialized[OPERATIONS].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - description_ = SerializationToolbox::ReadString(serialized, DESCRIPTION); - trailingTimeout_ = boost::posix_time::milliseconds - (SerializationToolbox::ReadUnsignedInteger(serialized, TRAILING_TIMEOUT)); - current_ = SerializationToolbox::ReadUnsignedInteger(serialized, CURRENT); - - const Json::Value& ops = serialized[OPERATIONS]; - - // Unserialize the individual operations - operations_.reserve(ops.size()); - for (Json::Value::ArrayIndex i = 0; i < ops.size(); i++) - { - operations_.push_back(new Operation(unserializer, i, ops[i])); - } - - // Connect the next operations - for (Json::Value::ArrayIndex i = 0; i < ops.size(); i++) - { - if (!ops[i].isMember(NEXT_OPERATIONS) || - ops[i][NEXT_OPERATIONS].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - const Json::Value& next = ops[i][NEXT_OPERATIONS]; - for (Json::Value::ArrayIndex j = 0; j < next.size(); j++) - { - if (next[j].type() != Json::intValue || - next[j].asInt() < 0 || - next[j].asUInt() >= operations_.size()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - operations_[i]->AddNextOperation(*operations_[next[j].asUInt()], true); - } - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/SequenceOfOperationsJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,159 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IJob.h" -#include "IJobOperation.h" - -#include -#include - -#include - -namespace Orthanc -{ - class SequenceOfOperationsJob : public IJob - { - public: - class IObserver : public boost::noncopyable - { - public: - virtual ~IObserver() - { - } - - virtual void SignalDone(const SequenceOfOperationsJob& job) = 0; - }; - - private: - class Operation; - - std::string description_; - bool done_; - boost::mutex mutex_; - std::vector operations_; - size_t current_; - boost::condition_variable operationAdded_; - boost::posix_time::time_duration trailingTimeout_; - std::list observers_; - - void NotifyDone() const; - - public: - SequenceOfOperationsJob(); - - SequenceOfOperationsJob(IJobUnserializer& unserializer, - const Json::Value& serialized); - - virtual ~SequenceOfOperationsJob(); - - void SetDescription(const std::string& description); - - void GetDescription(std::string& description); - - void Register(IObserver& observer); - - // This lock allows adding new operations to the end of the job, - // from another thread than the worker thread, after the job has - // been submitted for processing - class Lock : public boost::noncopyable - { - private: - SequenceOfOperationsJob& that_; - boost::mutex::scoped_lock lock_; - - public: - Lock(SequenceOfOperationsJob& that) : - that_(that), - lock_(that.mutex_) - { - } - - bool IsDone() const - { - return that_.done_; - } - - void SetTrailingOperationTimeout(unsigned int timeout); - - size_t AddOperation(IJobOperation* operation); - - size_t GetOperationsCount() const - { - return that_.operations_.size(); - } - - void AddInput(size_t index, - const JobOperationValue& value); - - void Connect(size_t input, - size_t output); - }; - - virtual void Start() ORTHANC_OVERRIDE - { - } - - virtual JobStepResult Step(const std::string& jobId) ORTHANC_OVERRIDE; - - virtual void Reset() ORTHANC_OVERRIDE; - - virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE - { - } - - virtual float GetProgress() ORTHANC_OVERRIDE; - - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE - { - target = "SequenceOfOperations"; - } - - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; - - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE; - - virtual bool GetOutput(std::string& output, - MimeType& mime, - const std::string& key) ORTHANC_OVERRIDE - { - return false; - } - - void AwakeTrailingSleep() - { - operationAdded_.notify_one(); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/StringOperationValue.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/StringOperationValue.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/StringOperationValue.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/Operations/StringOperationValue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "JobOperationValue.h" - -#include - -namespace Orthanc -{ - class StringOperationValue : public JobOperationValue - { - private: - std::string content_; - - public: - StringOperationValue(const std::string& content) : - JobOperationValue(JobOperationValue::Type_String), - content_(content) - { - } - - virtual JobOperationValue* Clone() const - { - return new StringOperationValue(content_); - } - - const std::string& GetContent() const - { - return content_; - } - - virtual void Serialize(Json::Value& target) const - { - target = Json::objectValue; - target["Type"] = "String"; - target["Content"] = content_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,303 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "SetOfCommandsJob.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../SerializationToolbox.h" - -#include -#include - -namespace Orthanc -{ - SetOfCommandsJob::SetOfCommandsJob() : - started_(false), - permissive_(false), - position_(0) - { - } - - - SetOfCommandsJob::~SetOfCommandsJob() - { - for (size_t i = 0; i < commands_.size(); i++) - { - assert(commands_[i] != NULL); - delete commands_[i]; - } - } - - - void SetOfCommandsJob::Reserve(size_t size) - { - if (started_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - commands_.reserve(size); - } - } - - - void SetOfCommandsJob::AddCommand(ICommand* command) - { - if (command == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else if (started_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - commands_.push_back(command); - } - } - - - void SetOfCommandsJob::SetPermissive(bool permissive) - { - if (started_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - permissive_ = permissive; - } - } - - - void SetOfCommandsJob::Reset() - { - if (started_) - { - position_ = 0; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - float SetOfCommandsJob::GetProgress() - { - if (commands_.empty()) - { - return 1; - } - else - { - return (static_cast(position_) / - static_cast(commands_.size())); - } - } - - - const SetOfCommandsJob::ICommand& SetOfCommandsJob::GetCommand(size_t index) const - { - if (index >= commands_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - assert(commands_[index] != NULL); - return *commands_[index]; - } - } - - - JobStepResult SetOfCommandsJob::Step(const std::string& jobId) - { - if (!started_) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (commands_.empty() && - position_ == 0) - { - // No command to handle: We're done - position_ = 1; - return JobStepResult::Success(); - } - - if (position_ >= commands_.size()) - { - // Already done - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - try - { - // Not at the trailing step: Handle the current command - if (!commands_[position_]->Execute(jobId)) - { - // Error - if (!permissive_) - { - return JobStepResult::Failure(ErrorCode_InternalError, NULL); - } - } - } - catch (OrthancException& e) - { - if (permissive_) - { - LOG(WARNING) << "Ignoring an error in a permissive job: " << e.What(); - } - else - { - return JobStepResult::Failure(e); - } - } - - position_ += 1; - - if (position_ == commands_.size()) - { - // We're done - return JobStepResult::Success(); - } - else - { - return JobStepResult::Continue(); - } - } - - - - static const char* KEY_DESCRIPTION = "Description"; - static const char* KEY_PERMISSIVE = "Permissive"; - static const char* KEY_POSITION = "Position"; - static const char* KEY_TYPE = "Type"; - static const char* KEY_COMMANDS = "Commands"; - - - void SetOfCommandsJob::GetPublicContent(Json::Value& value) - { - value[KEY_DESCRIPTION] = GetDescription(); - } - - - bool SetOfCommandsJob::Serialize(Json::Value& target) - { - target = Json::objectValue; - - std::string type; - GetJobType(type); - target[KEY_TYPE] = type; - - target[KEY_PERMISSIVE] = permissive_; - target[KEY_POSITION] = static_cast(position_); - target[KEY_DESCRIPTION] = description_; - - target[KEY_COMMANDS] = Json::arrayValue; - Json::Value& tmp = target[KEY_COMMANDS]; - - for (size_t i = 0; i < commands_.size(); i++) - { - assert(commands_[i] != NULL); - - Json::Value command; - commands_[i]->Serialize(command); - tmp.append(command); - } - - return true; - } - - - SetOfCommandsJob::SetOfCommandsJob(ICommandUnserializer* unserializer, - const Json::Value& source) : - started_(false) - { - std::unique_ptr raii(unserializer); - - permissive_ = SerializationToolbox::ReadBoolean(source, KEY_PERMISSIVE); - position_ = SerializationToolbox::ReadUnsignedInteger(source, KEY_POSITION); - description_ = SerializationToolbox::ReadString(source, KEY_DESCRIPTION); - - if (!source.isMember(KEY_COMMANDS) || - source[KEY_COMMANDS].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - const Json::Value& tmp = source[KEY_COMMANDS]; - commands_.resize(tmp.size()); - - for (Json::Value::ArrayIndex i = 0; i < tmp.size(); i++) - { - try - { - commands_[i] = unserializer->Unserialize(tmp[i]); - } - catch (OrthancException&) - { - } - - if (commands_[i] == NULL) - { - for (size_t j = 0; j < i; j++) - { - delete commands_[j]; - } - - throw OrthancException(ErrorCode_BadFileFormat); - } - } - } - - if (commands_.empty()) - { - if (position_ > 1) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - else if (position_ > commands_.size()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfCommandsJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,142 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IJob.h" - -#include - -namespace Orthanc -{ - class SetOfCommandsJob : public IJob - { - public: - class ICommand : public boost::noncopyable - { - public: - virtual ~ICommand() - { - } - - virtual bool Execute(const std::string& jobId) = 0; - - virtual void Serialize(Json::Value& target) const = 0; - }; - - class ICommandUnserializer : public boost::noncopyable - { - public: - virtual ~ICommandUnserializer() - { - } - - virtual ICommand* Unserialize(const Json::Value& source) const = 0; - }; - - private: - bool started_; - std::vector commands_; - bool permissive_; - size_t position_; - std::string description_; - - public: - SetOfCommandsJob(); - - SetOfCommandsJob(ICommandUnserializer* unserializer /* takes ownership */, - const Json::Value& source); - - virtual ~SetOfCommandsJob(); - - size_t GetPosition() const - { - return position_; - } - - void SetDescription(const std::string& description) - { - description_ = description; - } - - const std::string& GetDescription() const - { - return description_; - } - - void Reserve(size_t size); - - size_t GetCommandsCount() const - { - return commands_.size(); - } - - void AddCommand(ICommand* command); // Takes ownership - - bool IsPermissive() const - { - return permissive_; - } - - void SetPermissive(bool permissive); - - virtual void Reset() ORTHANC_OVERRIDE; - - virtual void Start() ORTHANC_OVERRIDE - { - started_ = true; - } - - virtual float GetProgress() ORTHANC_OVERRIDE; - - bool IsStarted() const - { - return started_; - } - - const ICommand& GetCommand(size_t index) const; - - virtual JobStepResult Step(const std::string& jobId) ORTHANC_OVERRIDE; - - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; - - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; - - virtual bool GetOutput(std::string& output, - MimeType& mime, - const std::string& key) ORTHANC_OVERRIDE - { - return false; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,252 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "SetOfInstancesJob.h" - -#include "../OrthancException.h" -#include "../SerializationToolbox.h" - -#include - -namespace Orthanc -{ - class SetOfInstancesJob::InstanceCommand : public SetOfInstancesJob::ICommand - { - private: - SetOfInstancesJob& that_; - std::string instance_; - - public: - InstanceCommand(SetOfInstancesJob& that, - const std::string& instance) : - that_(that), - instance_(instance) - { - } - - const std::string& GetInstance() const - { - return instance_; - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - if (!that_.HandleInstance(instance_)) - { - that_.failedInstances_.insert(instance_); - return false; - } - else - { - return true; - } - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - target = instance_; - } - }; - - - class SetOfInstancesJob::TrailingStepCommand : public SetOfInstancesJob::ICommand - { - private: - SetOfInstancesJob& that_; - - public: - TrailingStepCommand(SetOfInstancesJob& that) : - that_(that) - { - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - return that_.HandleTrailingStep(); - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - target = Json::nullValue; - } - }; - - - class SetOfInstancesJob::InstanceUnserializer : - public SetOfInstancesJob::ICommandUnserializer - { - private: - SetOfInstancesJob& that_; - - public: - InstanceUnserializer(SetOfInstancesJob& that) : - that_(that) - { - } - - virtual ICommand* Unserialize(const Json::Value& source) const - { - if (source.type() == Json::nullValue) - { - return new TrailingStepCommand(that_); - } - else if (source.type() == Json::stringValue) - { - return new InstanceCommand(that_, source.asString()); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - }; - - - SetOfInstancesJob::SetOfInstancesJob() : - hasTrailingStep_(false) - { - } - - - void SetOfInstancesJob::AddInstance(const std::string& instance) - { - AddCommand(new InstanceCommand(*this, instance)); - } - - - void SetOfInstancesJob::AddTrailingStep() - { - AddCommand(new TrailingStepCommand(*this)); - hasTrailingStep_ = true; - } - - - size_t SetOfInstancesJob::GetInstancesCount() const - { - if (hasTrailingStep_) - { - assert(GetCommandsCount() > 0); - return GetCommandsCount() - 1; - } - else - { - return GetCommandsCount(); - } - } - - - const std::string& SetOfInstancesJob::GetInstance(size_t index) const - { - if (index >= GetInstancesCount()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return dynamic_cast(GetCommand(index)).GetInstance(); - } - } - - - void SetOfInstancesJob::Start() - { - SetOfCommandsJob::Start(); - } - - - void SetOfInstancesJob::Reset() - { - SetOfCommandsJob::Reset(); - - failedInstances_.clear(); - } - - - static const char* KEY_TRAILING_STEP = "TrailingStep"; - static const char* KEY_FAILED_INSTANCES = "FailedInstances"; - static const char* KEY_PARENT_RESOURCES = "ParentResources"; - - void SetOfInstancesJob::GetPublicContent(Json::Value& target) - { - SetOfCommandsJob::GetPublicContent(target); - target["InstancesCount"] = static_cast(GetInstancesCount()); - target["FailedInstancesCount"] = static_cast(failedInstances_.size()); - - if (!parentResources_.empty()) - { - SerializationToolbox::WriteSetOfStrings(target, parentResources_, KEY_PARENT_RESOURCES); - } - } - - - bool SetOfInstancesJob::Serialize(Json::Value& target) - { - if (SetOfCommandsJob::Serialize(target)) - { - target[KEY_TRAILING_STEP] = hasTrailingStep_; - SerializationToolbox::WriteSetOfStrings(target, failedInstances_, KEY_FAILED_INSTANCES); - SerializationToolbox::WriteSetOfStrings(target, parentResources_, KEY_PARENT_RESOURCES); - return true; - } - else - { - return false; - } - } - - - SetOfInstancesJob::SetOfInstancesJob(const Json::Value& source) : - SetOfCommandsJob(new InstanceUnserializer(*this), source) - { - SerializationToolbox::ReadSetOfStrings(failedInstances_, source, KEY_FAILED_INSTANCES); - - if (source.isMember(KEY_PARENT_RESOURCES)) - { - // Backward compatibility with Orthanc <= 1.5.6 - SerializationToolbox::ReadSetOfStrings(parentResources_, source, KEY_PARENT_RESOURCES); - } - - if (source.isMember(KEY_TRAILING_STEP)) - { - hasTrailingStep_ = SerializationToolbox::ReadBoolean(source, KEY_TRAILING_STEP); - } - else - { - // Backward compatibility with Orthanc <= 1.4.2 - hasTrailingStep_ = false; - } - } - - -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/JobsEngine/SetOfInstancesJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IJob.h" -#include "SetOfCommandsJob.h" - -#include - -namespace Orthanc -{ - class SetOfInstancesJob : public SetOfCommandsJob - { - private: - class InstanceCommand; - class TrailingStepCommand; - class InstanceUnserializer; - - bool hasTrailingStep_; - std::set failedInstances_; - std::set parentResources_; - - protected: - virtual bool HandleInstance(const std::string& instance) = 0; - - virtual bool HandleTrailingStep() = 0; - - // Hiding this method, use AddInstance() instead - using SetOfCommandsJob::AddCommand; - - public: - SetOfInstancesJob(); - - SetOfInstancesJob(const Json::Value& source); // Unserialization - - // Only used for reporting in the public content - // https://groups.google.com/d/msg/orthanc-users/9GCV88GLEzw/6wAgP_PRAgAJ - void AddParentResource(const std::string& resource) - { - parentResources_.insert(resource); - } - - void AddInstance(const std::string& instance); - - void AddTrailingStep(); - - size_t GetInstancesCount() const; - - const std::string& GetInstance(size_t index) const; - - bool HasTrailingStep() const - { - return hasTrailingStep_; - } - - const std::set& GetFailedInstances() const - { - return failedInstances_; - } - - bool IsFailedInstance(const std::string& instance) const - { - return failedInstances_.find(instance) != failedInstances_.end(); - } - - virtual void Start(); - - virtual void Reset(); - - virtual void GetPublicContent(Json::Value& target); - - virtual bool Serialize(Json::Value& target); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,843 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "Logging.h" - -#if ORTHANC_ENABLE_LOGGING != 1 - -namespace Orthanc -{ - namespace Logging - { - void Initialize() - { - } - - void Finalize() - { - } - - void Reset() - { - } - - void Flush() - { - } - - void EnableInfoLevel(bool enabled) - { - } - - void EnableTraceLevel(bool enabled) - { - } - - bool IsTraceLevelEnabled() - { - return false; - } - - bool IsInfoLevelEnabled() - { - return false; - } - - void SetTargetFile(const std::string& path) - { - } - - void SetTargetFolder(const std::string& path) - { - } - } -} - - -#elif ORTHANC_ENABLE_LOGGING_PLUGIN == 1 - -/********************************************************* - * Logger compatible with the Orthanc plugin SDK - *********************************************************/ - -#include -#include - -namespace Orthanc -{ - namespace Logging - { - static OrthancPluginContext* context_ = NULL; - - void Initialize(OrthancPluginContext* context) - { - context_ = context; - } - - InternalLogger::InternalLogger(InternalLevel level, - const char* file /* ignored */, - int line /* ignored */) : - level_(level) - { - } - - InternalLogger::~InternalLogger() - { - std::string message = messageStream_.str(); - if (context_ != NULL) - { - switch (level_) - { - case InternalLevel_ERROR: - OrthancPluginLogError(context_, message.c_str()); - break; - - case InternalLevel_WARNING: - OrthancPluginLogWarning(context_, message.c_str()); - break; - - case InternalLevel_INFO: - OrthancPluginLogInfo(context_, message.c_str()); - break; - - case InternalLevel_TRACE: - // Not used by plugins - break; - - default: - { - std::string s = ("Unknown log level (" + boost::lexical_cast(level_) + - ") for message: " + message); - OrthancPluginLogError(context_, s.c_str()); - break; - } - } - } - } - } -} - - -#elif ORTHANC_ENABLE_LOGGING_STDIO == 1 - -/********************************************************* - * Logger compatible with OR logger that sends its - * output to the emscripten html5 api (depending on the - * definition of __EMSCRIPTEN__) - *********************************************************/ - -#include -#include - -#ifdef __EMSCRIPTEN__ -# include -#endif - -namespace Orthanc -{ - namespace Logging - { - static bool globalVerbose_ = false; - static bool globalTrace_ = false; - -#ifdef __EMSCRIPTEN__ - void defaultErrorLogFunc(const char* msg) - { - emscripten_console_error(msg); - } - - void defaultWarningLogFunc(const char* msg) - { - emscripten_console_warn(msg); - } - - void defaultInfoLogFunc(const char* msg) - { - emscripten_console_log(msg); - } - - void defaultTraceLogFunc(const char* msg) - { - emscripten_console_log(msg); - } -#else -// __EMSCRIPTEN__ not #defined - void defaultErrorLogFunc(const char* msg) - { - fprintf(stderr, "E: %s\n", msg); - } - - void defaultWarningLogFunc(const char*) - { - fprintf(stdout, "W: %s\n", msg); - } - - void defaultInfoLogFunc(const char*) - { - fprintf(stdout, "I: %s\n", msg); - } - - void defaultTraceLogFunc(const char*) - { - fprintf(stdout, "T: %s\n", msg); - } -#endif -// __EMSCRIPTEN__ - - static LoggingFunction globalErrorLogFunc = defaultErrorLogFunc; - static LoggingFunction globalWarningLogFunc = defaultWarningLogFunc; - static LoggingFunction globalInfoLogFunc = defaultInfoLogFunc; - static LoggingFunction globalTraceLogFunc = defaultTraceLogFunc; - - void SetErrorWarnInfoTraceLoggingFunctions( - LoggingFunction errorLogFunc, - LoggingFunction warningLogfunc, - LoggingFunction infoLogFunc, - LoggingFunction traceLogFunc) - { - globalErrorLogFunc = errorLogFunc; - globalWarningLogFunc = warningLogfunc; - globalInfoLogFunc = infoLogFunc; - globalTraceLogFunc = traceLogFunc; - } - - InternalLogger::InternalLogger(InternalLevel level, - const char* file /* ignored */, - int line /* ignored */) : - level_(level) - { - } - - InternalLogger::~InternalLogger() - { - std::string message = messageStream_.str(); - - switch (level_) - { - case InternalLevel_ERROR: - globalErrorLogFunc(message.c_str()); - break; - - case InternalLevel_WARNING: - globalWarningLogFunc(message.c_str()); - break; - - case InternalLevel_INFO: - if (globalVerbose_) - { - globalInfoLogFunc(message.c_str()); - // TODO: stone_console_info(message_.c_str()); - } - break; - - case InternalLevel_TRACE: - if (globalTrace_) - { - globalTraceLogFunc(message.c_str()); - } - break; - - default: - { - std::stringstream ss; - ss << "Unknown log level (" << level_ << ") for message: " << message; - std::string s = ss.str(); - globalErrorLogFunc(s.c_str()); - } - } - } - - void Initialize() - { - } - - void EnableInfoLevel(bool enabled) - { - globalVerbose_ = enabled; - } - - bool IsInfoLevelEnabled() - { - return globalVerbose_; - } - - void EnableTraceLevel(bool enabled) - { - globalTrace_ = enabled; - } - - bool IsTraceLevelEnabled() - { - return globalTrace_; - } - - } -} - - -#else /* ORTHANC_ENABLE_LOGGING_PLUGIN == 0 && - ORTHANC_ENABLE_LOGGING_STDIO == 0 && - ORTHANC_ENABLE_LOGGING == 1 */ - -/********************************************************* - * Internal logger of Orthanc, that mimics some - * behavior from Google Log. - *********************************************************/ - -#include "Compatibility.h" -#include "OrthancException.h" -#include "Enumerations.h" -#include "Toolbox.h" - -#if ORTHANC_SANDBOXED == 1 -# include -#else -# include "SystemToolbox.h" -#endif - -#include -#include -#include -#include - - -namespace -{ - struct LoggingContext - { - bool infoEnabled_; - bool traceEnabled_; - std::string targetFile_; - std::string targetFolder_; - - std::ostream* error_; - std::ostream* warning_; - std::ostream* info_; - - std::unique_ptr file_; - - LoggingContext() : - infoEnabled_(false), - traceEnabled_(false), - error_(&std::cerr), - warning_(&std::cerr), - info_(&std::cerr) - { - } - }; - - struct LoggingMementoImpl - { - bool valid_; - bool infoEnabled_; - bool traceEnabled_; - std::string targetFile_; - std::string targetFolder_; - - std::ostream* error_; - std::ostream* warning_; - std::ostream* info_; - }; -} - - - -static std::unique_ptr loggingContext_; -static boost::mutex loggingMutex_; - - - -namespace Orthanc -{ - namespace Logging - { - static void GetLogPath(boost::filesystem::path& log, - boost::filesystem::path& link, - const std::string& suffix, - const std::string& directory) - { - /** - From Google Log documentation: - - Unless otherwise specified, logs will be written to the filename - "...log.", - followed by the date, time, and pid (you can't prevent the date, - time, and pid from being in the filename). - - In this implementation : "hostname" and "username" are not used - **/ - - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - boost::filesystem::path root(directory); - boost::filesystem::path exe(SystemToolbox::GetPathToExecutable()); - - if (!boost::filesystem::exists(root) || - !boost::filesystem::is_directory(root)) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - char date[64]; - sprintf(date, "%04d%02d%02d-%02d%02d%02d.%d", - static_cast(now.date().year()), - now.date().month().as_number(), - now.date().day().as_number(), - static_cast(now.time_of_day().hours()), - static_cast(now.time_of_day().minutes()), - static_cast(now.time_of_day().seconds()), - SystemToolbox::GetProcessId()); - - std::string programName = exe.filename().replace_extension("").string(); - - log = (root / (programName + ".log" + suffix + "." + std::string(date))); - link = (root / (programName + ".log" + suffix)); - } - - - static void PrepareLogFolder(std::unique_ptr& file, - const std::string& suffix, - const std::string& directory) - { - boost::filesystem::path log, link; - GetLogPath(log, link, suffix, directory); - -#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) - boost::filesystem::remove(link); - boost::filesystem::create_symlink(log.filename(), link); -#endif - - file.reset(new std::ofstream(log.string().c_str())); - } - - - void Initialize() - { - boost::mutex::scoped_lock lock(loggingMutex_); - loggingContext_.reset(new LoggingContext); - } - - void Finalize() - { - boost::mutex::scoped_lock lock(loggingMutex_); - loggingContext_.reset(NULL); - } - - void Reset() - { - // Recover the old logging context - std::unique_ptr old; - - { - boost::mutex::scoped_lock lock(loggingMutex_); - if (loggingContext_.get() == NULL) - { - return; - } - else - { -#if __cplusplus < 201103L - old.reset(loggingContext_.release()); -#else - old = std::move(loggingContext_); -#endif - - // Create a new logging context, - loggingContext_.reset(new LoggingContext); - } - } - - EnableInfoLevel(old->infoEnabled_); - EnableTraceLevel(old->traceEnabled_); - - if (!old->targetFolder_.empty()) - { - SetTargetFolder(old->targetFolder_); - } - else if (!old->targetFile_.empty()) - { - SetTargetFile(old->targetFile_); - } - } - - - LoggingMemento CreateLoggingMemento() - { - LoggingMementoImpl* memento = new LoggingMementoImpl(); - - memento->valid_ = true; - { - boost::mutex::scoped_lock lock(loggingMutex_); - memento->infoEnabled_ = loggingContext_->infoEnabled_; - memento->traceEnabled_ = loggingContext_->traceEnabled_; - memento->targetFile_ = loggingContext_->targetFile_; - memento->targetFolder_ = loggingContext_->targetFolder_; - - memento->error_ = loggingContext_->error_; - memento->warning_ = loggingContext_->warning_; - memento->info_ = loggingContext_->info_; - } - return reinterpret_cast(memento); - } - - void RestoreLoggingMemento(LoggingMemento mementoPtr) - { - LoggingMementoImpl* memento = - reinterpret_cast(mementoPtr); - if (!memento->valid_) - throw std::runtime_error("Memento already used"); - memento->valid_ = false; - std::unique_ptr deleter(memento); - { - boost::mutex::scoped_lock lock(loggingMutex_); - loggingContext_.reset(new LoggingContext); - loggingContext_->error_ = memento->error_; - loggingContext_->warning_ = memento->warning_; - loggingContext_->info_ = memento->info_; - } - EnableInfoLevel(memento->infoEnabled_); - EnableTraceLevel(memento->traceEnabled_); - if (!memento->targetFolder_.empty()) - { - SetTargetFolder(memento->targetFolder_); - } - else if (!memento->targetFile_.empty()) - { - SetTargetFile(memento->targetFile_); - } - } - - void DiscardLoggingMemento(LoggingMemento mementoPtr) - { - LoggingMementoImpl* memento = - reinterpret_cast(mementoPtr); - delete memento; - } - - void EnableInfoLevel(bool enabled) - { - boost::mutex::scoped_lock lock(loggingMutex_); - assert(loggingContext_.get() != NULL); - - loggingContext_->infoEnabled_ = enabled; - - if (!enabled) - { - // Also disable the "TRACE" level when info-level debugging is disabled - loggingContext_->traceEnabled_ = false; - } - } - - bool IsInfoLevelEnabled() - { - boost::mutex::scoped_lock lock(loggingMutex_); - assert(loggingContext_.get() != NULL); - - return loggingContext_->infoEnabled_; - } - - void EnableTraceLevel(bool enabled) - { - boost::mutex::scoped_lock lock(loggingMutex_); - assert(loggingContext_.get() != NULL); - - loggingContext_->traceEnabled_ = enabled; - - if (enabled) - { - // Also enable the "INFO" level when trace-level debugging is enabled - loggingContext_->infoEnabled_ = true; - } - } - - bool IsTraceLevelEnabled() - { - boost::mutex::scoped_lock lock(loggingMutex_); - assert(loggingContext_.get() != NULL); - - return loggingContext_->traceEnabled_; - } - - - static void CheckFile(std::unique_ptr& f) - { - if (loggingContext_->file_.get() == NULL || - !loggingContext_->file_->is_open()) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - } - - void SetTargetFolder(const std::string& path) - { - boost::mutex::scoped_lock lock(loggingMutex_); - assert(loggingContext_.get() != NULL); - - PrepareLogFolder(loggingContext_->file_, "" /* no suffix */, path); - CheckFile(loggingContext_->file_); - - loggingContext_->targetFile_.clear(); - loggingContext_->targetFolder_ = path; - loggingContext_->warning_ = loggingContext_->file_.get(); - loggingContext_->error_ = loggingContext_->file_.get(); - loggingContext_->info_ = loggingContext_->file_.get(); - } - - - void SetTargetFile(const std::string& path) - { - boost::mutex::scoped_lock lock(loggingMutex_); - assert(loggingContext_.get() != NULL); - - loggingContext_->file_.reset(new std::ofstream(path.c_str(), std::fstream::app)); - CheckFile(loggingContext_->file_); - - loggingContext_->targetFile_ = path; - loggingContext_->targetFolder_.clear(); - loggingContext_->warning_ = loggingContext_->file_.get(); - loggingContext_->error_ = loggingContext_->file_.get(); - loggingContext_->info_ = loggingContext_->file_.get(); - } - - - InternalLogger::InternalLogger(const char* level, - const char* file, - int line) : - lock_(loggingMutex_), - stream_(&null_) // By default, logging to "/dev/null" is simulated - { - if (loggingContext_.get() == NULL) - { - fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n"); - return; - } - - try - { - LogLevel l = StringToLogLevel(level); - - if ((l == LogLevel_Info && !loggingContext_->infoEnabled_) || - (l == LogLevel_Trace && !loggingContext_->traceEnabled_)) - { - // This logging level is disabled, directly exit and unlock - // the mutex to speed-up things. The stream is set to "/dev/null" - lock_.unlock(); - return; - } - - // Compute the header of the line, temporary release the lock as - // this is a time-consuming operation - lock_.unlock(); - std::string header; - - { - boost::filesystem::path path(file); - boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time(); - boost::posix_time::time_duration duration = now.time_of_day(); - - /** - From Google Log documentation: - - "Log lines have this form: - - Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg... - - where the fields are defined as follows: - - L A single character, representing the log level (eg 'I' for INFO) - mm The month (zero padded; ie May is '05') - dd The day (zero padded) - hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds - threadid The space-padded thread ID as returned by GetTID() (this matches the PID on Linux) - file The file name - line The line number - msg The user-supplied message" - - In this implementation, "threadid" is not printed. - **/ - - char date[64]; - sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ", - level[0], - now.date().month().as_number(), - now.date().day().as_number(), - static_cast(duration.hours()), - static_cast(duration.minutes()), - static_cast(duration.seconds()), - static_cast(duration.fractional_seconds())); - - header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast(line) + "] "; - } - - - // The header is computed, we now re-lock the mutex to access - // the stream objects. Pay attention that "loggingContext_", - // "infoEnabled_" or "traceEnabled_" might have changed while - // the mutex was unlocked. - lock_.lock(); - - if (loggingContext_.get() == NULL) - { - fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n"); - return; - } - - switch (l) - { - case LogLevel_Error: - stream_ = loggingContext_->error_; - break; - - case LogLevel_Warning: - stream_ = loggingContext_->warning_; - break; - - case LogLevel_Info: - if (loggingContext_->infoEnabled_) - { - stream_ = loggingContext_->info_; - } - - break; - - case LogLevel_Trace: - if (loggingContext_->traceEnabled_) - { - stream_ = loggingContext_->info_; - } - - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - if (stream_ == &null_) - { - // The logging is disabled for this level. The stream is the - // "null_" member of this object, so we can release the global - // mutex. - lock_.unlock(); - } - - (*stream_) << header; - } - catch (...) - { - // Something is going really wrong, probably running out of - // memory. Fallback to a degraded mode. - stream_ = loggingContext_->error_; - (*stream_) << "E???? ??:??:??.?????? ] "; - } - } - - - InternalLogger::~InternalLogger() - { - if (stream_ != &null_) - { - *stream_ << "\n"; - stream_->flush(); - } - } - - - void Flush() - { - boost::mutex::scoped_lock lock(loggingMutex_); - - if (loggingContext_.get() != NULL && - loggingContext_->file_.get() != NULL) - { - loggingContext_->file_->flush(); - } - } - - void SetErrorWarnInfoLoggingStreams(std::ostream* errorStream, - std::ostream* warningStream, - std::ostream* infoStream) - { - boost::mutex::scoped_lock lock(loggingMutex_); - std::unique_ptr old; - -#if __cplusplus < 201103L - old.reset(loggingContext_.release()); -#else - old = std::move(loggingContext_); -#endif - - loggingContext_.reset(new LoggingContext); - loggingContext_->error_ = errorStream; - loggingContext_->warning_ = warningStream; - loggingContext_->info_ = infoStream; - lock.unlock(); - EnableInfoLevel(old->infoEnabled_); - EnableTraceLevel(old->traceEnabled_); - } - -#ifdef __EMSCRIPTEN__ - - FuncStreamBuf - globalEmscriptenErrorStreamBuf(emscripten_console_error); - std::unique_ptr globalEmscriptenErrorStream; - - FuncStreamBuf - globalEmscriptenWarningStreamBuf(emscripten_console_warn); - std::unique_ptr globalEmscriptenWarningStream; - - FuncStreamBuf - globalEmscriptenInfoStreamBuf(emscripten_console_log); - std::unique_ptr globalEmscriptenInfoStream; - - void EnableEmscriptenLogging() - { - globalEmscriptenErrorStream.reset(new ostream( - &globalEmscriptenErrorStreamBuf)); - - globalEmscriptenWarningStream.reset(new ostream( - &globalEmscriptenWarningStreamBuf)); - - globalEmscriptenInfoStream.reset(new ostream( - &globalEmscriptenInfoStreamBuf)); - - SetErrorWarnInfoLoggingStreams( - &globalEmscriptenErrorStream, - &globalEmscriptenWarningStream - &globalEmscriptenInfoStream); - } -#endif - } -} - - -#endif // ORTHANC_ENABLE_LOGGING diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Logging.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,268 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ -#pragma once - -#include - -#if !defined(ORTHANC_ENABLE_LOGGING) -# error The macro ORTHANC_ENABLE_LOGGING must be defined -#endif - -#if !defined(ORTHANC_ENABLE_LOGGING_PLUGIN) -# if ORTHANC_ENABLE_LOGGING == 1 -# error The macro ORTHANC_ENABLE_LOGGING_PLUGIN must be defined -# else -# define ORTHANC_ENABLE_LOGGING_PLUGIN 0 -# endif -#endif - -#if !defined(ORTHANC_ENABLE_LOGGING_STDIO) -# if ORTHANC_ENABLE_LOGGING == 1 -# error The macro ORTHANC_ENABLE_LOGGING_STDIO must be defined -# else -# define ORTHANC_ENABLE_LOGGING_STDIO 0 -# endif -#endif - -#if ORTHANC_ENABLE_LOGGING_PLUGIN == 1 -# include -#endif - -#include - -namespace Orthanc -{ - namespace Logging - { -#if ORTHANC_ENABLE_LOGGING_PLUGIN == 1 - void Initialize(OrthancPluginContext* context); -#else - void Initialize(); -#endif - - void Finalize(); - - void Reset(); - - void Flush(); - - void EnableInfoLevel(bool enabled); - - void EnableTraceLevel(bool enabled); - - bool IsTraceLevelEnabled(); - - bool IsInfoLevelEnabled(); - - void SetTargetFile(const std::string& path); - - void SetTargetFolder(const std::string& path); - -#if ORTHANC_ENABLE_LOGGING_STDIO == 1 - typedef void (*LoggingFunction)(const char*); - void SetErrorWarnInfoTraceLoggingFunctions( - LoggingFunction errorLogFunc, - LoggingFunction warningLogfunc, - LoggingFunction infoLogFunc, - LoggingFunction traceLogFunc); -#endif - - - struct NullStream : public std::ostream - { - NullStream() : - std::ios(0), - std::ostream(0) - { - } - - template - std::ostream& operator<< (const T& message) - { - return *this; - } - }; - } -} - -#if ORTHANC_ENABLE_LOGGING != 1 - -# define LOG(level) ::Orthanc::Logging::NullStream() -# define VLOG(level) ::Orthanc::Logging::NullStream() - -#elif (ORTHANC_ENABLE_LOGGING_PLUGIN == 1 || \ - ORTHANC_ENABLE_LOGGING_STDIO == 1) - -# include -# define LOG(level) ::Orthanc::Logging::InternalLogger \ - (::Orthanc::Logging::InternalLevel_ ## level, __FILE__, __LINE__) -# define VLOG(level) ::Orthanc::Logging::InternalLogger \ - (::Orthanc::Logging::InternalLevel_TRACE, __FILE__, __LINE__) - -namespace Orthanc -{ - namespace Logging - { - enum InternalLevel - { - InternalLevel_ERROR, - InternalLevel_WARNING, - InternalLevel_INFO, - InternalLevel_TRACE - }; - - class InternalLogger : public boost::noncopyable - { - private: - InternalLevel level_; - std::stringstream messageStream_; - - public: - InternalLogger(InternalLevel level, - const char* file, - int line); - - ~InternalLogger(); - - template - InternalLogger& operator<< (const T& message) - { - messageStream_ << message; - return *this; - } - }; - } -} - - - - -#else /* ORTHANC_ENABLE_LOGGING_PLUGIN == 0 && - ORTHANC_ENABLE_LOGGING_STDIO == 0 && - ORTHANC_ENABLE_LOGGING == 1 */ - -# include -# define LOG(level) ::Orthanc::Logging::InternalLogger(#level, __FILE__, __LINE__) -# define VLOG(level) ::Orthanc::Logging::InternalLogger("TRACE", __FILE__, __LINE__) - -namespace Orthanc -{ - namespace Logging - { - class InternalLogger - { - private: - boost::mutex::scoped_lock lock_; - NullStream null_; - std::ostream* stream_; - - public: - InternalLogger(const char* level, - const char* file, - int line); - - ~InternalLogger(); - - template - std::ostream& operator<< (const T& message) - { - return (*stream_) << boost::lexical_cast(message); - } - }; - - /** - opaque pointer that represents the state of the logging configuration - */ - typedef void* LoggingMemento; - - /** - Returns an object that contains the logging configuration. - - This function allocates resources that you must dispose of by - using either RestoreLoggingMemento or DiscardLoggingMemento. - - This function is only to be used by tests. - */ - LoggingMemento CreateLoggingMemento(); - - /** - Restores the logging configuration. The logging system is restored in - the state it was in when the memento object was created through - GetLoggingMemento(). - - After calling this function, the memento object may not be used - again - - This function is only to be used by tests. - */ - void RestoreLoggingMemento(LoggingMemento memento); - - /** - Call this function if you do not plan on restoring the logging - configuration state that you captured with CreateLoggingMemento - - This function is only to be used by tests. - */ - void DiscardLoggingMemento(LoggingMemento memento); - - /** - Set custom logging streams for the error, warning and info logs. - This function may not be called if a log file or folder has been - set beforehand. All three pointers must be valid and cannot be NULL. - - Please ensure the supplied streams remain alive and valid as long as - logging calls are performed. - - In order to prevent dangling pointer usage, it is recommended to call - Orthanc::Logging::Reset() before the stream objects are destroyed and - the pointers become invalid. - */ - void SetErrorWarnInfoLoggingStreams(std::ostream* errorStream, - std::ostream* warningStream, - std::ostream* infoStream); - -#ifdef __EMSCRIPTEN__ - /** - This function will change the logging streams so that the logging functions - provided by emscripten html5.h API functions are used : it will change the - error_, warning_ and info_ stream objects so that their operator<< writes - into the browser console using emscripten_console_error(), - emscripten_console_warn() and emscripten_console_log(). This will allow for - logging levels to be correctly handled by the browser when the code executes - in Web Assembly - */ - void EnableEmscriptenLogging(); -#endif - } -} - -#endif // ORTHANC_ENABLE_LOGGING diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/LoggingUtils.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/LoggingUtils.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/LoggingUtils.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/LoggingUtils.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -#include -#include - -namespace Orthanc -{ - namespace Logging - { - - /** - std::streambuf subclass used in FunctionCallingStream - */ - template - class FuncStreamBuf : public std::stringbuf - { - public: - FuncStreamBuf(T func) : func_(func) {} - - virtual int sync() - { - std::string text = this->str(); - const char* buf = text.c_str(); - func_(buf); - this->str(""); - return 0; - } - private: - T func_; - }; - } -} \ No newline at end of file diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,681 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "LuaContext.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#include -#include -#include - -extern "C" -{ -#include -#include -} - -namespace Orthanc -{ - static bool OnlyContainsDigits(const std::string& s) - { - for (size_t i = 0; i < s.size(); i++) - { - if (!isdigit(s[i])) - { - return false; - } - } - - return true; - } - - LuaContext& LuaContext::GetLuaContext(lua_State *state) - { - const void* value = GetGlobalVariable(state, "_LuaContext"); - assert(value != NULL); - - return *const_cast(reinterpret_cast(value)); - } - - int LuaContext::PrintToLog(lua_State *state) - { - LuaContext& that = GetLuaContext(state); - - // http://medek.wordpress.com/2009/02/03/wrapping-lua-errors-and-print-function/ - int nArgs = lua_gettop(state); - lua_getglobal(state, "tostring"); - - // Make sure you start at 1 *NOT* 0 for arrays in Lua. - std::string result; - - for (int i = 1; i <= nArgs; i++) - { - const char *s; - lua_pushvalue(state, -1); - lua_pushvalue(state, i); - lua_call(state, 1, 1); - s = lua_tostring(state, -1); - - if (result.size() > 0) - result.append(", "); - - if (s == NULL) - result.append(""); - else - result.append(s); - - lua_pop(state, 1); - } - - LOG(WARNING) << "Lua says: " << result; - that.log_.append(result); - that.log_.append("\n"); - - return 0; - } - - - int LuaContext::ParseJson(lua_State *state) - { - LuaContext& that = GetLuaContext(state); - - int nArgs = lua_gettop(state); - if (nArgs != 1 || - !lua_isstring(state, 1)) // Password - { - lua_pushnil(state); - return 1; - } - - const char* str = lua_tostring(state, 1); - - Json::Value value; - Json::Reader reader; - if (reader.parse(str, str + strlen(str), value)) - { - that.PushJson(value); - } - else - { - lua_pushnil(state); - } - - return 1; - } - - - int LuaContext::DumpJson(lua_State *state) - { - LuaContext& that = GetLuaContext(state); - - int nArgs = lua_gettop(state); - if ((nArgs != 1 && nArgs != 2) || - (nArgs == 2 && !lua_isboolean(state, 2))) - { - lua_pushnil(state); - return 1; - } - - bool keepStrings = false; - if (nArgs == 2) - { - keepStrings = lua_toboolean(state, 2) ? true : false; - } - - Json::Value json; - that.GetJson(json, state, 1, keepStrings); - - Json::FastWriter writer; - std::string s = writer.write(json); - lua_pushlstring(state, s.c_str(), s.size()); - - return 1; - } - - - int LuaContext::SetHttpCredentials(lua_State *state) - { - LuaContext& that = GetLuaContext(state); - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if (nArgs != 2 || - !lua_isstring(state, 1) || // Username - !lua_isstring(state, 2)) // Password - { - LOG(ERROR) << "Lua: Bad parameters to SetHttpCredentials()"; - } - else - { - // Configure the HTTP client - const char* username = lua_tostring(state, 1); - const char* password = lua_tostring(state, 2); - that.httpClient_.SetCredentials(username, password); - } - - return 0; - } - - - bool LuaContext::AnswerHttpQuery(lua_State* state) - { - std::string str; - - try - { - httpClient_.Apply(str); - } - catch (OrthancException&) - { - return false; - } - - // Return the result of the HTTP request - lua_pushlstring(state, str.c_str(), str.size()); - - return true; - } - - - void LuaContext::SetHttpHeaders(int top) - { - std::map headers; - GetDictionaryArgument(headers, lua_, top, false /* keep key case as provided by Lua script */); - - httpClient_.ClearHeaders(); // always reset headers in case they have been set in a previous request - - for (std::map::const_iterator - it = headers.begin(); it != headers.end(); ++it) - { - httpClient_.AddHeader(it->first, it->second); - } - } - - - int LuaContext::CallHttpGet(lua_State *state) - { - LuaContext& that = GetLuaContext(state); - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if (nArgs < 1 || nArgs > 2 || // check args count - !lua_isstring(state, 1)) // URL is a string - { - LOG(ERROR) << "Lua: Bad parameters to HttpGet()"; - lua_pushnil(state); - return 1; - } - - // Configure the HTTP client class - const char* url = lua_tostring(state, 1); - that.httpClient_.SetMethod(HttpMethod_Get); - that.httpClient_.SetUrl(url); - that.httpClient_.GetBody().clear(); - that.SetHttpHeaders(2); - - // Do the HTTP GET request - if (!that.AnswerHttpQuery(state)) - { - LOG(ERROR) << "Lua: Error in HttpGet() for URL " << url; - lua_pushnil(state); - } - - return 1; - } - - - int LuaContext::CallHttpPostOrPut(lua_State *state, - HttpMethod method) - { - LuaContext& that = GetLuaContext(state); - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if ((nArgs < 1 || nArgs > 3) || // check arg count - !lua_isstring(state, 1) || // URL is a string - (nArgs >= 2 && (!lua_isstring(state, 2) && !lua_isnil(state, 2)))) // Body data is null or is a string - { - LOG(ERROR) << "Lua: Bad parameters to HttpPost() or HttpPut()"; - lua_pushnil(state); - return 1; - } - - // Configure the HTTP client class - const char* url = lua_tostring(state, 1); - that.httpClient_.SetMethod(method); - that.httpClient_.SetUrl(url); - that.SetHttpHeaders(3); - - if (nArgs >= 2 && !lua_isnil(state, 2)) - { - size_t bodySize = 0; - const char* bodyData = lua_tolstring(state, 2, &bodySize); - - if (bodySize == 0) - { - that.httpClient_.GetBody().clear(); - } - else - { - that.httpClient_.GetBody().assign(bodyData, bodySize); - } - } - else - { - that.httpClient_.GetBody().clear(); - } - - // Do the HTTP POST/PUT request - if (!that.AnswerHttpQuery(state)) - { - LOG(ERROR) << "Lua: Error in HttpPost() or HttpPut() for URL " << url; - lua_pushnil(state); - } - - return 1; - } - - - int LuaContext::CallHttpPost(lua_State *state) - { - return CallHttpPostOrPut(state, HttpMethod_Post); - } - - - int LuaContext::CallHttpPut(lua_State *state) - { - return CallHttpPostOrPut(state, HttpMethod_Put); - } - - - int LuaContext::CallHttpDelete(lua_State *state) - { - LuaContext& that = GetLuaContext(state); - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if (nArgs < 1 || nArgs > 2 || !lua_isstring(state, 1)) // URL - { - LOG(ERROR) << "Lua: Bad parameters to HttpDelete()"; - lua_pushnil(state); - return 1; - } - - // Configure the HTTP client class - const char* url = lua_tostring(state, 1); - that.httpClient_.SetMethod(HttpMethod_Delete); - that.httpClient_.SetUrl(url); - that.httpClient_.GetBody().clear(); - that.SetHttpHeaders(2); - - // Do the HTTP DELETE request - std::string s; - if (!that.httpClient_.Apply(s)) - { - LOG(ERROR) << "Lua: Error in HttpDelete() for URL " << url; - lua_pushnil(state); - } - else - { - lua_pushstring(state, "SUCCESS"); - } - - return 1; - } - - - void LuaContext::PushJson(const Json::Value& value) - { - if (value.isString()) - { - const std::string s = value.asString(); - lua_pushlstring(lua_, s.c_str(), s.size()); - } - else if (value.isDouble()) - { - lua_pushnumber(lua_, value.asDouble()); - } - else if (value.isInt()) - { - lua_pushinteger(lua_, value.asInt()); - } - else if (value.isUInt()) - { - lua_pushinteger(lua_, value.asUInt()); - } - else if (value.isBool()) - { - lua_pushboolean(lua_, value.asBool()); - } - else if (value.isNull()) - { - lua_pushnil(lua_); - } - else if (value.isArray()) - { - lua_newtable(lua_); - - // http://lua-users.org/wiki/SimpleLuaApiExample - for (Json::Value::ArrayIndex i = 0; i < value.size(); i++) - { - // Push the table index (note the "+1" because of Lua conventions) - lua_pushnumber(lua_, i + 1); - - // Push the value of the cell - PushJson(value[i]); - - // Stores the pair in the table - lua_rawset(lua_, -3); - } - } - else if (value.isObject()) - { - lua_newtable(lua_); - - Json::Value::Members members = value.getMemberNames(); - - for (Json::Value::Members::const_iterator - it = members.begin(); it != members.end(); ++it) - { - // Push the index of the cell - lua_pushlstring(lua_, it->c_str(), it->size()); - - // Push the value of the cell - PushJson(value[*it]); - - // Stores the pair in the table - lua_rawset(lua_, -3); - } - } - else - { - throw OrthancException(ErrorCode_JsonToLuaTable); - } - } - - - void LuaContext::GetJson(Json::Value& result, - lua_State* state, - int top, - bool keepStrings) - { - if (lua_istable(state, top)) - { - Json::Value tmp = Json::objectValue; - bool isArray = true; - size_t size = 0; - - // Code adapted from: http://stackoverflow.com/a/6142700/881731 - - // Push another reference to the table on top of the stack (so we know - // where it is, and this function can work for negative, positive and - // pseudo indices - lua_pushvalue(state, top); - // stack now contains: -1 => table - lua_pushnil(state); - // stack now contains: -1 => nil; -2 => table - while (lua_next(state, -2)) - { - // stack now contains: -1 => value; -2 => key; -3 => table - // copy the key so that lua_tostring does not modify the original - lua_pushvalue(state, -2); - // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table - std::string key(lua_tostring(state, -1)); - Json::Value v; - GetJson(v, state, -2, keepStrings); - - tmp[key] = v; - - size += 1; - try - { - if (!OnlyContainsDigits(key) || - boost::lexical_cast(key) != size) - { - isArray = false; - } - } - catch (boost::bad_lexical_cast&) - { - isArray = false; - } - - // pop value + copy of key, leaving original key - lua_pop(state, 2); - // stack now contains: -1 => key; -2 => table - } - // stack now contains: -1 => table (when lua_next returns 0 it pops the key - // but does not push anything.) - // Pop table - lua_pop(state, 1); - - // Stack is now the same as it was on entry to this function - - if (isArray) - { - result = Json::arrayValue; - for (size_t i = 0; i < size; i++) - { - result.append(tmp[boost::lexical_cast(i + 1)]); - } - } - else - { - result = tmp; - } - } - else if (lua_isnil(state, top)) - { - result = Json::nullValue; - } - else if (!keepStrings && - lua_isboolean(state, top)) - { - result = lua_toboolean(state, top) ? true : false; - } - else if (!keepStrings && - lua_isnumber(state, top)) - { - // Convert to "int" if truncation does not loose precision - double value = static_cast(lua_tonumber(state, top)); - int truncated = static_cast(value); - - if (std::abs(value - static_cast(truncated)) <= - std::numeric_limits::epsilon()) - { - result = truncated; - } - else - { - result = value; - } - } - else if (lua_isstring(state, top)) - { - // Caution: The "lua_isstring()" case must be the last, since - // Lua can convert most types to strings by default. - result = std::string(lua_tostring(state, top)); - } - else if (lua_isboolean(state, top)) - { - result = lua_toboolean(state, top) ? true : false; - } - else - { - LOG(WARNING) << "Unsupported Lua type when returning Json"; - result = Json::nullValue; - } - } - - - LuaContext::LuaContext() - { - lua_ = luaL_newstate(); - if (!lua_) - { - throw OrthancException(ErrorCode_CannotCreateLua); - } - - luaL_openlibs(lua_); - lua_register(lua_, "print", PrintToLog); - lua_register(lua_, "ParseJson", ParseJson); - lua_register(lua_, "DumpJson", DumpJson); - lua_register(lua_, "HttpGet", CallHttpGet); - lua_register(lua_, "HttpPost", CallHttpPost); - lua_register(lua_, "HttpPut", CallHttpPut); - lua_register(lua_, "HttpDelete", CallHttpDelete); - lua_register(lua_, "SetHttpCredentials", SetHttpCredentials); - - SetGlobalVariable("_LuaContext", this); - } - - - LuaContext::~LuaContext() - { - lua_close(lua_); - } - - - void LuaContext::ExecuteInternal(std::string* output, - const std::string& command) - { - log_.clear(); - int error = (luaL_loadbuffer(lua_, command.c_str(), command.size(), "line") || - lua_pcall(lua_, 0, 0, 0)); - - if (error) - { - assert(lua_gettop(lua_) >= 1); - - std::string description(lua_tostring(lua_, -1)); - lua_pop(lua_, 1); /* pop error message from the stack */ - throw OrthancException(ErrorCode_CannotExecuteLua, description); - } - - if (output != NULL) - { - *output = log_; - } - } - - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 - void LuaContext::Execute(EmbeddedResources::FileResourceId resource) - { - std::string command; - EmbeddedResources::GetFileResource(command, resource); - ExecuteInternal(NULL, command); - } -#endif - - - bool LuaContext::IsExistingFunction(const char* name) - { - lua_settop(lua_, 0); - lua_getglobal(lua_, name); - return lua_type(lua_, -1) == LUA_TFUNCTION; - } - - - void LuaContext::Execute(Json::Value& output, - const std::string& command) - { - std::string s; - ExecuteInternal(&s, command); - - Json::Reader reader; - if (!reader.parse(s, output)) - { - throw OrthancException(ErrorCode_BadJson); - } - } - - - void LuaContext::RegisterFunction(const char* name, - lua_CFunction func) - { - lua_register(lua_, name, func); - } - - - void LuaContext::SetGlobalVariable(const char* name, - void* value) - { - lua_pushlightuserdata(lua_, value); - lua_setglobal(lua_, name); - } - - - const void* LuaContext::GetGlobalVariable(lua_State* state, - const char* name) - { - lua_getglobal(state, name); - assert(lua_type(state, -1) == LUA_TLIGHTUSERDATA); - const void* value = lua_topointer(state, -1); - lua_pop(state, 1); - return value; - } - - - void LuaContext::GetDictionaryArgument(std::map& target, - lua_State* state, - int top, - bool keyToLowerCase) - { - target.clear(); - - if (lua_gettop(state) >= top) - { - Json::Value headers; - GetJson(headers, state, top, true); - - Json::Value::Members members = headers.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - std::string key = members[i]; - - if (keyToLowerCase) - { - Toolbox::ToLowerCase(key); - } - - target[key] = headers[members[i]].asString(); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaContext.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_LUA) -# error The macro ORTHANC_ENABLE_LUA must be defined -#endif - -#if !defined(ORTHANC_HAS_EMBEDDED_RESOURCES) -# error Macro ORTHANC_HAS_EMBEDDED_RESOURCES must be defined -#endif - -#if ORTHANC_ENABLE_LUA == 0 -# error The Lua support is disabled, cannot include this file -#endif - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 -# include // Autogenerated file -#endif - -#include "../HttpClient.h" - -extern "C" -{ -#include -} - -#include - -namespace Orthanc -{ - class LuaContext : public boost::noncopyable - { - private: - friend class LuaFunctionCall; - - lua_State *lua_; - std::string log_; - HttpClient httpClient_; - - static int PrintToLog(lua_State *state); - static int ParseJson(lua_State *state); - static int DumpJson(lua_State *state); - - static int SetHttpCredentials(lua_State *state); - - static int CallHttpPostOrPut(lua_State *state, - HttpMethod method); - static int CallHttpGet(lua_State *state); - static int CallHttpPost(lua_State *state); - static int CallHttpPut(lua_State *state); - static int CallHttpDelete(lua_State *state); - - bool AnswerHttpQuery(lua_State* state); - - void ExecuteInternal(std::string* output, - const std::string& command); - - static void GetJson(Json::Value& result, - lua_State* state, - int top, - bool keepStrings); - - void SetHttpHeaders(int top); - - public: - LuaContext(); - - ~LuaContext(); - - void Execute(const std::string& command) - { - ExecuteInternal(NULL, command); - } - - void Execute(std::string& output, - const std::string& command) - { - ExecuteInternal(&output, command); - } - - void Execute(Json::Value& output, - const std::string& command); - -#if ORTHANC_HAS_EMBEDDED_RESOURCES == 1 - void Execute(EmbeddedResources::FileResourceId resource); -#endif - - bool IsExistingFunction(const char* name); - - void SetHttpCredentials(const char* username, - const char* password) - { - httpClient_.SetCredentials(username, password); - } - - void RegisterFunction(const char* name, - lua_CFunction func); - - void SetGlobalVariable(const char* name, - void* value); - - static LuaContext& GetLuaContext(lua_State *state); - - static const void* GetGlobalVariable(lua_State* state, - const char* name); - - void PushJson(const Json::Value& value); - - static void GetDictionaryArgument(std::map& target, - lua_State* state, - int top, - bool keyToLowerCase); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "LuaFunctionCall.h" - -#include "../OrthancException.h" -#include "../Logging.h" - -#include -#include -#include - -namespace Orthanc -{ - void LuaFunctionCall::CheckAlreadyExecuted() - { - if (isExecuted_) - { - throw OrthancException(ErrorCode_LuaAlreadyExecuted); - } - } - - LuaFunctionCall::LuaFunctionCall(LuaContext& context, - const char* functionName) : - context_(context), - isExecuted_(false) - { - // Clear the stack to fulfill the invariant - lua_settop(context_.lua_, 0); - lua_getglobal(context_.lua_, functionName); - } - - void LuaFunctionCall::PushString(const std::string& value) - { - CheckAlreadyExecuted(); - lua_pushlstring(context_.lua_, value.c_str(), value.size()); - } - - void LuaFunctionCall::PushBoolean(bool value) - { - CheckAlreadyExecuted(); - lua_pushboolean(context_.lua_, value); - } - - void LuaFunctionCall::PushInteger(int value) - { - CheckAlreadyExecuted(); - lua_pushinteger(context_.lua_, value); - } - - void LuaFunctionCall::PushDouble(double value) - { - CheckAlreadyExecuted(); - lua_pushnumber(context_.lua_, value); - } - - void LuaFunctionCall::PushJson(const Json::Value& value) - { - CheckAlreadyExecuted(); - context_.PushJson(value); - } - - void LuaFunctionCall::ExecuteInternal(int numOutputs) - { - CheckAlreadyExecuted(); - - assert(lua_gettop(context_.lua_) >= 1); - int nargs = lua_gettop(context_.lua_) - 1; - int error = lua_pcall(context_.lua_, nargs, numOutputs, 0); - - if (error) - { - assert(lua_gettop(context_.lua_) >= 1); - - std::string description(lua_tostring(context_.lua_, -1)); - lua_pop(context_.lua_, 1); /* pop error message from the stack */ - - throw OrthancException(ErrorCode_CannotExecuteLua, description); - } - - if (lua_gettop(context_.lua_) < numOutputs) - { - throw OrthancException(ErrorCode_LuaBadOutput); - } - - isExecuted_ = true; - } - - bool LuaFunctionCall::ExecutePredicate() - { - ExecuteInternal(1); - - if (!lua_isboolean(context_.lua_, 1)) - { - throw OrthancException(ErrorCode_NotLuaPredicate); - } - - return lua_toboolean(context_.lua_, 1) != 0; - } - - - void LuaFunctionCall::ExecuteToJson(Json::Value& result, - bool keepStrings) - { - ExecuteInternal(1); - context_.GetJson(result, context_.lua_, lua_gettop(context_.lua_), keepStrings); - } - - - void LuaFunctionCall::ExecuteToString(std::string& result) - { - ExecuteInternal(1); - - int top = lua_gettop(context_.lua_); - if (lua_isstring(context_.lua_, top)) - { - result = lua_tostring(context_.lua_, top); - } - else - { - throw OrthancException(ErrorCode_LuaReturnsNoString); - } - } - - - void LuaFunctionCall::PushStringMap(const std::map& value) - { - Json::Value json = Json::objectValue; - - for (std::map::const_iterator - it = value.begin(); it != value.end(); ++it) - { - json[it->first] = it->second; - } - - PushJson(json); - } - - - void LuaFunctionCall::PushDicom(const DicomMap& dicom) - { - DicomArray a(dicom); - PushDicom(a); - } - - - void LuaFunctionCall::PushDicom(const DicomArray& dicom) - { - Json::Value value = Json::objectValue; - - for (size_t i = 0; i < dicom.GetSize(); i++) - { - const DicomValue& v = dicom.GetElement(i).GetValue(); - std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent(); - value[dicom.GetElement(i).GetTag().Format()] = s; - } - - PushJson(value); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Lua/LuaFunctionCall.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,93 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "LuaContext.h" - -#include "../DicomFormat/DicomArray.h" -#include "../DicomFormat/DicomMap.h" - -#include - -namespace Orthanc -{ - class LuaFunctionCall : public boost::noncopyable - { - private: - LuaContext& context_; - bool isExecuted_; - - void CheckAlreadyExecuted(); - - protected: - void ExecuteInternal(int numOutputs); - - lua_State* GetState() - { - return context_.lua_; - } - - public: - LuaFunctionCall(LuaContext& context, - const char* functionName); - - void PushString(const std::string& value); - - void PushBoolean(bool value); - - void PushInteger(int value); - - void PushDouble(double value); - - void PushJson(const Json::Value& value); - - void PushStringMap(const std::map& value); - - void PushDicom(const DicomMap& dicom); - - void PushDicom(const DicomArray& dicom); - - void Execute() - { - ExecuteInternal(0); - } - - bool ExecutePredicate(); - - void ExecuteToJson(Json::Value& result, - bool keepStrings); - - void ExecuteToString(std::string& result); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,330 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "MetricsRegistry.h" - -#include "ChunkedBuffer.h" -#include "Compatibility.h" -#include "OrthancException.h" - -namespace Orthanc -{ - static const boost::posix_time::ptime GetNow() - { - return boost::posix_time::microsec_clock::universal_time(); - } - - class MetricsRegistry::Item - { - private: - MetricsType type_; - boost::posix_time::ptime time_; - bool hasValue_; - float value_; - - void Touch(float value, - const boost::posix_time::ptime& now) - { - hasValue_ = true; - value_ = value; - time_ = now; - } - - void Touch(float value) - { - Touch(value, GetNow()); - } - - void UpdateMax(float value, - int duration) - { - if (hasValue_) - { - const boost::posix_time::ptime now = GetNow(); - - if (value > value_ || - (now - time_).total_seconds() > duration) - { - Touch(value, now); - } - } - else - { - Touch(value); - } - } - - void UpdateMin(float value, - int duration) - { - if (hasValue_) - { - const boost::posix_time::ptime now = GetNow(); - - if (value < value_ || - (now - time_).total_seconds() > duration) - { - Touch(value, now); - } - } - else - { - Touch(value); - } - } - - public: - Item(MetricsType type) : - type_(type), - hasValue_(false) - { - } - - MetricsType GetType() const - { - return type_; - } - - void Update(float value) - { - switch (type_) - { - case MetricsType_Default: - Touch(value); - break; - - case MetricsType_MaxOver10Seconds: - UpdateMax(value, 10); - break; - - case MetricsType_MaxOver1Minute: - UpdateMax(value, 60); - break; - - case MetricsType_MinOver10Seconds: - UpdateMin(value, 10); - break; - - case MetricsType_MinOver1Minute: - UpdateMin(value, 60); - break; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - bool HasValue() const - { - return hasValue_; - } - - const boost::posix_time::ptime& GetTime() const - { - if (hasValue_) - { - return time_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - float GetValue() const - { - if (hasValue_) - { - return value_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - }; - - - MetricsRegistry::~MetricsRegistry() - { - for (Content::iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(it->second != NULL); - delete it->second; - } - } - - - void MetricsRegistry::SetEnabled(bool enabled) - { - boost::mutex::scoped_lock lock(mutex_); - enabled_ = enabled; - } - - - void MetricsRegistry::Register(const std::string& name, - MetricsType type) - { - boost::mutex::scoped_lock lock(mutex_); - - Content::iterator found = content_.find(name); - - if (found == content_.end()) - { - content_[name] = new Item(type); - } - else - { - assert(found->second != NULL); - - // This metrics already exists: Only recreate it if there is a - // mismatch in the type of metrics - if (found->second->GetType() != type) - { - delete found->second; - found->second = new Item(type); - } - } - } - - - void MetricsRegistry::SetValueInternal(const std::string& name, - float value, - MetricsType type) - { - boost::mutex::scoped_lock lock(mutex_); - - Content::iterator found = content_.find(name); - - if (found == content_.end()) - { - std::unique_ptr item(new Item(type)); - item->Update(value); - content_[name] = item.release(); - } - else - { - assert(found->second != NULL); - found->second->Update(value); - } - } - - - MetricsType MetricsRegistry::GetMetricsType(const std::string& name) - { - boost::mutex::scoped_lock lock(mutex_); - - Content::const_iterator found = content_.find(name); - - if (found == content_.end()) - { - throw OrthancException(ErrorCode_InexistentItem); - } - else - { - assert(found->second != NULL); - return found->second->GetType(); - } - } - - - void MetricsRegistry::ExportPrometheusText(std::string& s) - { - // https://www.boost.org/doc/libs/1_69_0/doc/html/date_time/examples.html#date_time.examples.seconds_since_epoch - static const boost::posix_time::ptime EPOCH(boost::gregorian::date(1970, 1, 1)); - - boost::mutex::scoped_lock lock(mutex_); - - s.clear(); - - if (!enabled_) - { - return; - } - - ChunkedBuffer buffer; - - for (Content::const_iterator it = content_.begin(); - it != content_.end(); ++it) - { - assert(it->second != NULL); - - if (it->second->HasValue()) - { - boost::posix_time::time_duration diff = it->second->GetTime() - EPOCH; - - std::string line = (it->first + " " + - boost::lexical_cast(it->second->GetValue()) + " " + - boost::lexical_cast(diff.total_milliseconds()) + "\n"); - - buffer.AddChunk(line); - } - } - - buffer.Flatten(s); - } - - - void MetricsRegistry::SharedMetrics::Add(float delta) - { - boost::mutex::scoped_lock lock(mutex_); - value_ += delta; - registry_.SetValue(name_, value_); - } - - - void MetricsRegistry::Timer::Start() - { - if (registry_.IsEnabled()) - { - active_ = true; - start_ = GetNow(); - } - else - { - active_ = false; - } - } - - - MetricsRegistry::Timer::~Timer() - { - if (active_) - { - boost::posix_time::time_duration diff = GetNow() - start_; - registry_.SetValue( - name_, static_cast(diff.total_milliseconds()), type_); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MetricsRegistry.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,189 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The class MetricsRegistry cannot be used in sandboxed environments -#endif - -#include -#include - -namespace Orthanc -{ - enum MetricsType - { - MetricsType_Default, - MetricsType_MaxOver10Seconds, - MetricsType_MaxOver1Minute, - MetricsType_MinOver10Seconds, - MetricsType_MinOver1Minute - }; - - class MetricsRegistry : public boost::noncopyable - { - private: - class Item; - - typedef std::map Content; - - bool enabled_; - boost::mutex mutex_; - Content content_; - - void SetValueInternal(const std::string& name, - float value, - MetricsType type); - - public: - MetricsRegistry() : - enabled_(true) - { - } - - ~MetricsRegistry(); - - bool IsEnabled() const - { - return enabled_; - } - - void SetEnabled(bool enabled); - - void Register(const std::string& name, - MetricsType type); - - void SetValue(const std::string& name, - float value, - MetricsType type) - { - // Inlining to avoid loosing time if metrics are disabled - if (enabled_) - { - SetValueInternal(name, value, type); - } - } - - void SetValue(const std::string& name, - float value) - { - SetValue(name, value, MetricsType_Default); - } - - MetricsType GetMetricsType(const std::string& name); - - // https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format - void ExportPrometheusText(std::string& s); - - - class SharedMetrics : public boost::noncopyable - { - private: - boost::mutex mutex_; - MetricsRegistry& registry_; - std::string name_; - float value_; - - public: - SharedMetrics(MetricsRegistry& registry, - const std::string& name, - MetricsType type) : - registry_(registry), - name_(name), - value_(0) - { - } - - void Add(float delta); - }; - - - class ActiveCounter : public boost::noncopyable - { - private: - SharedMetrics& metrics_; - - public: - ActiveCounter(SharedMetrics& metrics) : - metrics_(metrics) - { - metrics_.Add(1); - } - - ~ActiveCounter() - { - metrics_.Add(-1); - } - }; - - - class Timer : public boost::noncopyable - { - private: - MetricsRegistry& registry_; - std::string name_; - MetricsType type_; - bool active_; - boost::posix_time::ptime start_; - - void Start(); - - public: - Timer(MetricsRegistry& registry, - const std::string& name) : - registry_(registry), - name_(name), - type_(MetricsType_MaxOver10Seconds) - { - Start(); - } - - Timer(MetricsRegistry& registry, - const std::string& name, - MetricsType type) : - registry_(registry), - name_(name), - type_(type) - { - Start(); - } - - ~Timer(); - }; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/IRunnableBySteps.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/IRunnableBySteps.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/IRunnableBySteps.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/IRunnableBySteps.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IDynamicObject.h" - -namespace Orthanc -{ - class IRunnableBySteps : public IDynamicObject - { - public: - virtual ~IRunnableBySteps() - { - } - - // Must return "true" if the runnable wishes to continue. Must - // return "false" if the runnable has not finished its job. - virtual bool Step() = 0; - - static void RunUntilDone(IRunnableBySteps& runnable) - { - while (runnable.Step()); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RunnableWorkersPool.h" - -#include "SharedMessageQueue.h" -#include "../Compatibility.h" -#include "../OrthancException.h" -#include "../Logging.h" - -namespace Orthanc -{ - struct RunnableWorkersPool::PImpl - { - class Worker - { - private: - const bool& continue_; - SharedMessageQueue& queue_; - boost::thread thread_; - - static void WorkerThread(Worker* that) - { - while (that->continue_) - { - try - { - std::unique_ptr obj(that->queue_.Dequeue(100)); - if (obj.get() != NULL) - { - IRunnableBySteps& runnable = *dynamic_cast(obj.get()); - - bool wishToContinue = runnable.Step(); - - if (wishToContinue) - { - // The runnable wishes to continue, reinsert it at the beginning of the queue - that->queue_.Enqueue(obj.release()); - } - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while handling some runnable object: " << e.What(); - } - catch (std::bad_alloc&) - { - LOG(ERROR) << "Not enough memory to handle some runnable object"; - } - catch (std::exception& e) - { - LOG(ERROR) << "std::exception while handling some runnable object: " << e.what(); - } - catch (...) - { - LOG(ERROR) << "Native exception while handling some runnable object"; - } - } - } - - public: - Worker(const bool& globalContinue, - SharedMessageQueue& queue) : - continue_(globalContinue), - queue_(queue) - { - thread_ = boost::thread(WorkerThread, this); - } - - void Join() - { - if (thread_.joinable()) - { - thread_.join(); - } - } - }; - - - bool continue_; - std::vector workers_; - SharedMessageQueue queue_; - }; - - - - RunnableWorkersPool::RunnableWorkersPool(size_t countWorkers) : pimpl_(new PImpl) - { - pimpl_->continue_ = true; - - if (countWorkers == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - pimpl_->workers_.resize(countWorkers); - - for (size_t i = 0; i < countWorkers; i++) - { - pimpl_->workers_[i] = new PImpl::Worker(pimpl_->continue_, pimpl_->queue_); - } - } - - - void RunnableWorkersPool::Stop() - { - if (pimpl_->continue_) - { - pimpl_->continue_ = false; - - for (size_t i = 0; i < pimpl_->workers_.size(); i++) - { - PImpl::Worker* worker = pimpl_->workers_[i]; - - if (worker != NULL) - { - worker->Join(); - delete worker; - } - } - } - } - - - RunnableWorkersPool::~RunnableWorkersPool() - { - Stop(); - } - - - void RunnableWorkersPool::Add(IRunnableBySteps* runnable) - { - if (!pimpl_->continue_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - pimpl_->queue_.Enqueue(runnable); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/RunnableWorkersPool.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IRunnableBySteps.h" - -#include - -namespace Orthanc -{ - class RunnableWorkersPool : public boost::noncopyable - { - private: - struct PImpl; - boost::shared_ptr pimpl_; - - void Stop(); - - public: - explicit RunnableWorkersPool(size_t countWorkers); - - ~RunnableWorkersPool(); - - void Add(IRunnableBySteps* runnable); // Takes the ownership - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "Semaphore.h" - -#include "../OrthancException.h" - - -namespace Orthanc -{ - Semaphore::Semaphore(unsigned int availableResources) : - availableResources_(availableResources) - { - if (availableResources_ == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - void Semaphore::Release() - { - boost::mutex::scoped_lock lock(mutex_); - - availableResources_++; - condition_.notify_one(); - } - - void Semaphore::Acquire() - { - boost::mutex::scoped_lock lock(mutex_); - - while (availableResources_ == 0) - { - condition_.wait(lock); - } - - availableResources_--; - } - - bool Semaphore::TryAcquire() - { - boost::mutex::scoped_lock lock(mutex_); - - if (availableResources_ == 0) - { - return false; - } - - availableResources_--; - return true; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/Semaphore.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include - -namespace Orthanc -{ - class Semaphore : public boost::noncopyable - { - private: - unsigned int availableResources_; - boost::mutex mutex_; - boost::condition_variable condition_; - - void Release(); - - void Acquire(); - - bool TryAcquire(); - public: - explicit Semaphore(unsigned int availableResources); - - unsigned int GetAvailableResourcesCount() const - { - return availableResources_; - } - - - class Locker : public boost::noncopyable - { - private: - Semaphore& that_; - - public: - explicit Locker(Semaphore& that) : - that_(that) - { - that_.Acquire(); - } - - ~Locker() - { - that_.Release(); - } - }; - - class TryLocker : public boost::noncopyable - { - private: - Semaphore& that_; - bool isAcquired_; - - public: - explicit TryLocker(Semaphore& that) : - that_(that) - { - isAcquired_ = that_.TryAcquire(); - } - - ~TryLocker() - { - if (isAcquired_) - { - that_.Release(); - } - } - - bool IsAcquired() const - { - return isAcquired_; - } - }; - - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,211 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "SharedMessageQueue.h" - - -#include "../Compatibility.h" - - -/** - * FIFO (queue): - * - * back front - * +--+--+--+--+--+--+--+--+--+--+--+ - * Enqueue -> | | | | | | | | | | | | - * | | | | | | | | | | | | -> Dequeue - * +--+--+--+--+--+--+--+--+--+--+--+ - * ^ - * | - * Make room here - * - * - * LIFO (stack): - * - * back front - * +--+--+--+--+--+--+--+--+--+--+--+ - * | | | | | | | | | | | | <- Enqueue - * | | | | | | | | | | | | -> Dequeue - * +--+--+--+--+--+--+--+--+--+--+--+ - * ^ - * | - * Make room here - **/ - - -namespace Orthanc -{ - SharedMessageQueue::SharedMessageQueue(unsigned int maxSize) : - isFifo_(true), - maxSize_(maxSize) - { - } - - - SharedMessageQueue::~SharedMessageQueue() - { - for (Queue::iterator it = queue_.begin(); it != queue_.end(); ++it) - { - delete *it; - } - } - - - void SharedMessageQueue::Enqueue(IDynamicObject* message) - { - boost::mutex::scoped_lock lock(mutex_); - - if (maxSize_ != 0 && queue_.size() > maxSize_) - { - if (isFifo_) - { - // Too many elements in the queue: Make room - delete queue_.front(); - queue_.pop_front(); - } - else - { - // Too many elements in the stack: Make room - delete queue_.back(); - queue_.pop_back(); - } - } - - if (isFifo_) - { - // Queue policy (FIFO) - queue_.push_back(message); - } - else - { - // Stack policy (LIFO) - queue_.push_front(message); - } - - elementAvailable_.notify_one(); - } - - - IDynamicObject* SharedMessageQueue::Dequeue(int32_t millisecondsTimeout) - { - boost::mutex::scoped_lock lock(mutex_); - - // Wait for a message to arrive in the FIFO queue - while (queue_.empty()) - { - if (millisecondsTimeout == 0) - { - elementAvailable_.wait(lock); - } - else - { - bool success = elementAvailable_.timed_wait - (lock, boost::posix_time::milliseconds(millisecondsTimeout)); - if (!success) - { - return NULL; - } - } - } - - std::unique_ptr message(queue_.front()); - queue_.pop_front(); - - if (queue_.empty()) - { - emptied_.notify_all(); - } - - return message.release(); - } - - - - bool SharedMessageQueue::WaitEmpty(int32_t millisecondsTimeout) - { - boost::mutex::scoped_lock lock(mutex_); - - // Wait for the queue to become empty - while (!queue_.empty()) - { - if (millisecondsTimeout == 0) - { - emptied_.wait(lock); - } - else - { - if (!emptied_.timed_wait - (lock, boost::posix_time::milliseconds(millisecondsTimeout))) - { - return false; - } - } - } - - return true; - } - - - void SharedMessageQueue::SetFifoPolicy() - { - boost::mutex::scoped_lock lock(mutex_); - isFifo_ = true; - } - - void SharedMessageQueue::SetLifoPolicy() - { - boost::mutex::scoped_lock lock(mutex_); - isFifo_ = false; - } - - void SharedMessageQueue::Clear() - { - boost::mutex::scoped_lock lock(mutex_); - - if (queue_.empty()) - { - return; - } - else - { - while (!queue_.empty()) - { - std::unique_ptr message(queue_.front()); - queue_.pop_front(); - } - - emptied_.notify_all(); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/MultiThreading/SharedMessageQueue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IDynamicObject.h" - -#include -#include -#include - -namespace Orthanc -{ - class SharedMessageQueue : public boost::noncopyable - { - private: - typedef std::list Queue; - - bool isFifo_; - unsigned int maxSize_; - Queue queue_; - boost::mutex mutex_; - boost::condition_variable elementAvailable_; - boost::condition_variable emptied_; - - public: - explicit SharedMessageQueue(unsigned int maxSize = 0); - - ~SharedMessageQueue(); - - // This transfers the ownership of the message - void Enqueue(IDynamicObject* message); - - // The caller is responsible to delete the dequeud message! - IDynamicObject* Dequeue(int32_t millisecondsTimeout); - - bool WaitEmpty(int32_t millisecondsTimeout); - - bool IsFifoPolicy() const - { - return isFifo_; - } - - bool IsLifoPolicy() const - { - return !isFifo_; - } - - void SetFifoPolicy(); - - void SetLifoPolicy(); - - void Clear(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/OrthancException.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/OrthancException.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/OrthancException.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/OrthancException.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,146 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "Compatibility.h" -#include "Enumerations.h" -#include "Logging.h" - -#include -#include -#include - -namespace Orthanc -{ - class OrthancException - { - private: - OrthancException(); // Forbidden - - OrthancException& operator= (const OrthancException&); // Forbidden - - ErrorCode errorCode_; - HttpStatus httpStatus_; - - // New in Orthanc 1.5.0 - std::unique_ptr details_; - - public: - OrthancException(const OrthancException& other) : - errorCode_(other.errorCode_), - httpStatus_(other.httpStatus_) - { - if (other.details_.get() != NULL) - { - details_.reset(new std::string(*other.details_)); - } - } - - explicit OrthancException(ErrorCode errorCode) : - errorCode_(errorCode), - httpStatus_(ConvertErrorCodeToHttpStatus(errorCode)) - { - } - - OrthancException(ErrorCode errorCode, - const std::string& details, - bool log = true) : - errorCode_(errorCode), - httpStatus_(ConvertErrorCodeToHttpStatus(errorCode)), - details_(new std::string(details)) - { -#if ORTHANC_ENABLE_LOGGING == 1 - if (log) - { - LOG(ERROR) << EnumerationToString(errorCode_) << ": " << details; - } -#endif - } - - OrthancException(ErrorCode errorCode, - HttpStatus httpStatus) : - errorCode_(errorCode), - httpStatus_(httpStatus) - { - } - - OrthancException(ErrorCode errorCode, - HttpStatus httpStatus, - const std::string& details, - bool log = true) : - errorCode_(errorCode), - httpStatus_(httpStatus), - details_(new std::string(details)) - { -#if ORTHANC_ENABLE_LOGGING == 1 - if (log) - { - LOG(ERROR) << EnumerationToString(errorCode_) << ": " << details; - } -#endif - } - - ErrorCode GetErrorCode() const - { - return errorCode_; - } - - HttpStatus GetHttpStatus() const - { - return httpStatus_; - } - - const char* What() const - { - return EnumerationToString(errorCode_); - } - - bool HasDetails() const - { - return details_.get() != NULL; - } - - const char* GetDetails() const - { - if (details_.get() == NULL) - { - return ""; - } - else - { - return details_->c_str(); - } - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,311 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "Pkcs11.h" - - -#if defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_ECDH) -# error OpenSSL was compiled without support for RSA, EC, ECDSA or ECDH -#endif - - -#include "Logging.h" -#include "OrthancException.h" -#include "SystemToolbox.h" - -extern "C" -{ -# include // This is P11's "engine.h" -# include -} - -#include - - -namespace Orthanc -{ - namespace Pkcs11 - { - static const char* PKCS11_ENGINE_ID = "pkcs11"; - static const char* PKCS11_ENGINE_NAME = "PKCS#11 for Orthanc"; - static const ENGINE_CMD_DEFN PKCS11_ENGINE_COMMANDS[] = - { - { - CMD_MODULE_PATH, - "MODULE_PATH", - "Specifies the path to the PKCS#11 module shared library", - ENGINE_CMD_FLAG_STRING - }, - { - CMD_PIN, - "PIN", - "Specifies the pin code", - ENGINE_CMD_FLAG_STRING - }, - { - CMD_VERBOSE, - "VERBOSE", - "Print additional details", - ENGINE_CMD_FLAG_NO_INPUT - }, - { - CMD_LOAD_CERT_CTRL, - "LOAD_CERT_CTRL", - "Get the certificate from card", - ENGINE_CMD_FLAG_INTERNAL - }, - { - 0, - NULL, - NULL, - 0 - } - }; - - - static bool pkcs11Initialized_ = false; - static ENGINE_CTX *context_ = NULL; - - static int EngineInitialize(ENGINE* engine) - { - if (context_ == NULL) - { - return 0; - } - else - { - return pkcs11_init(context_); - } - } - - - static int EngineFinalize(ENGINE* engine) - { - if (context_ == NULL) - { - return 0; - } - else - { - return pkcs11_finish(context_); - } - } - - - static int EngineDestroy(ENGINE* engine) - { - return (context_ == NULL ? 0 : 1); - } - - - static int EngineControl(ENGINE *engine, - int command, - long i, - void *p, - void (*f) ()) - { - if (context_ == NULL) - { - return 0; - } - else - { - return pkcs11_engine_ctrl(context_, command, i, p, f); - } - } - - - static EVP_PKEY *EngineLoadPublicKey(ENGINE *engine, - const char *s_key_id, - UI_METHOD *ui_method, - void *callback_data) - { - if (context_ == NULL) - { - return 0; - } - else - { - return pkcs11_load_public_key(context_, s_key_id, ui_method, callback_data); - } - } - - - static EVP_PKEY *EngineLoadPrivateKey(ENGINE *engine, - const char *s_key_id, - UI_METHOD *ui_method, - void *callback_data) - { - if (context_ == NULL) - { - return 0; - } - else - { - return pkcs11_load_private_key(context_, s_key_id, ui_method, callback_data); - } - } - - - static ENGINE* LoadEngine() - { - // This function creates an engine for PKCS#11 and inspired by - // the "ENGINE_load_dynamic" function from OpenSSL, in file - // "crypto/engine/eng_dyn.c" - - ENGINE* engine = ENGINE_new(); - if (!engine) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot create an OpenSSL engine for PKCS#11"); - } - - // Create a PKCS#11 context using libp11 - context_ = pkcs11_new(); - if (!context_) - { - ENGINE_free(engine); - throw OrthancException(ErrorCode_InternalError, - "Cannot create a libp11 context for PKCS#11"); - } - - if (!ENGINE_set_id(engine, PKCS11_ENGINE_ID) || - !ENGINE_set_name(engine, PKCS11_ENGINE_NAME) || - !ENGINE_set_cmd_defns(engine, PKCS11_ENGINE_COMMANDS) || - - // Register the callback functions - !ENGINE_set_init_function(engine, EngineInitialize) || - !ENGINE_set_finish_function(engine, EngineFinalize) || - !ENGINE_set_destroy_function(engine, EngineDestroy) || - !ENGINE_set_ctrl_function(engine, EngineControl) || - !ENGINE_set_load_pubkey_function(engine, EngineLoadPublicKey) || - !ENGINE_set_load_privkey_function(engine, EngineLoadPrivateKey) || - - !ENGINE_set_RSA(engine, PKCS11_get_rsa_method()) || - -#if OPENSSL_VERSION_NUMBER < 0x10100000L // OpenSSL 1.0.2 - !ENGINE_set_ECDSA(engine, PKCS11_get_ecdsa_method()) || - !ENGINE_set_ECDH(engine, PKCS11_get_ecdh_method()) || -#else - !ENGINE_set_EC(engine, PKCS11_get_ec_key_method()) || -#endif - - // Make OpenSSL know about our PKCS#11 engine - !ENGINE_add(engine)) - { - pkcs11_finish(context_); - ENGINE_free(engine); - throw OrthancException(ErrorCode_InternalError, - "Cannot initialize the OpenSSL engine for PKCS#11"); - } - - // If the "ENGINE_add" worked, it gets a structural - // reference. We release our just-created reference. - ENGINE_free(engine); - - return ENGINE_by_id(PKCS11_ENGINE_ID); - } - - - bool IsInitialized() - { - return pkcs11Initialized_; - } - - const char* GetEngineIdentifier() - { - return PKCS11_ENGINE_ID; - } - - void Initialize(const std::string& module, - const std::string& pin, - bool verbose) - { - if (pkcs11Initialized_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "The PKCS#11 engine has already been initialized"); - } - - if (module.empty() || - !SystemToolbox::IsRegularFile(module)) - { - throw OrthancException( - ErrorCode_InexistentFile, - "The PKCS#11 module must be a path to one shared library (DLL or .so)"); - } - - ENGINE* engine = LoadEngine(); - if (!engine) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot create an OpenSSL engine for PKCS#11"); - } - - if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", module.c_str(), 0)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot configure the OpenSSL dynamic engine for PKCS#11"); - } - - if (verbose) - { - ENGINE_ctrl_cmd_string(engine, "VERBOSE", NULL, 0); - } - - if (!pin.empty() && - !ENGINE_ctrl_cmd_string(engine, "PIN", pin.c_str(), 0)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot set the PIN code for PKCS#11"); - } - - if (!ENGINE_init(engine)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot initialize the OpenSSL dynamic engine for PKCS#11"); - } - - LOG(WARNING) << "The PKCS#11 engine has been successfully initialized"; - pkcs11Initialized_ = true; - } - - - void Finalize() - { - // Nothing to do, the unregistration of the engine is - // automatically done by OpenSSL - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Pkcs11.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if !defined(ORTHANC_ENABLE_PKCS11) -# error The macro ORTHANC_ENABLE_PKCS11 must be defined -#endif - -#if !defined(ORTHANC_ENABLE_SSL) -# error The macro ORTHANC_ENABLE_SSL must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error This file cannot be used in sandboxed environments -#endif - -#if ORTHANC_ENABLE_PKCS11 != 1 || ORTHANC_ENABLE_SSL != 1 -# error This file cannot be used if OpenSSL or PKCS#11 support is disabled -#endif - - -#include - -namespace Orthanc -{ - namespace Pkcs11 - { - const char* GetEngineIdentifier(); - - bool IsInitialized(); - - void Initialize(const std::string& module, - const std::string& pin, - bool verbose); - - void Finalize(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/PrecompiledHeaders.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if defined(_WIN32) && !defined(NOMINMAX) -#define NOMINMAX -#endif - -#if ORTHANC_USE_PRECOMPILED_HEADERS == 1 - -//#include -//#include -#include -//#include -//#include -#include -#include - -#include - -#if ORTHANC_ENABLE_PUGIXML == 1 -# include -#endif - -#include "../Core/Compatibility.h" -#include "Enumerations.h" -#include "Logging.h" -#include "OrthancException.h" -#include "Toolbox.h" - -#if ORTHANC_ENABLE_DCMTK == 1 -// Headers from DCMTK used in Orthanc headers -# include -# include -# include -# include -#endif - -#if ORTHANC_ENABLE_DCMTK_NETWORKING == 1 -# include "DicomNetworking/DicomServer.h" - -// Headers from DCMTK used in Orthanc headers -# include -#endif - -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RestApiCall.h" - -namespace Orthanc -{ - bool RestApiCall::ParseJsonRequestInternal(Json::Value& result, - const void* body, - size_t size) - { - result.clear(); - Json::Reader reader; - return reader.parse(reinterpret_cast(body), - reinterpret_cast(body) + size, result); - } - - - std::string RestApiCall::FlattenUri() const - { - std::string s = "/"; - - for (size_t i = 0; i < fullUri_.size(); i++) - { - s += fullUri_[i] + "/"; - } - - return s; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiCall.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,148 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../HttpServer/IHttpHandler.h" -#include "../HttpServer/HttpToolbox.h" -#include "RestApiPath.h" -#include "RestApiOutput.h" - -#include - -namespace Orthanc -{ - class RestApi; - - class RestApiCall : public boost::noncopyable - { - private: - RestApiOutput& output_; - RestApi& context_; - RequestOrigin origin_; - const char* remoteIp_; - const char* username_; - const IHttpHandler::Arguments& httpHeaders_; - const IHttpHandler::Arguments& uriComponents_; - const UriComponents& trailing_; - const UriComponents& fullUri_; - - protected: - static bool ParseJsonRequestInternal(Json::Value& result, - const void* body, - size_t size); - - public: - RestApiCall(RestApiOutput& output, - RestApi& context, - RequestOrigin origin, - const char* remoteIp, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::Arguments& uriComponents, - const UriComponents& trailing, - const UriComponents& fullUri) : - output_(output), - context_(context), - origin_(origin), - remoteIp_(remoteIp), - username_(username), - httpHeaders_(httpHeaders), - uriComponents_(uriComponents), - trailing_(trailing), - fullUri_(fullUri) - { - } - - RestApiOutput& GetOutput() - { - return output_; - } - - RestApi& GetContext() - { - return context_; - } - - const UriComponents& GetFullUri() const - { - return fullUri_; - } - - const UriComponents& GetTrailingUri() const - { - return trailing_; - } - - std::string GetUriComponent(const std::string& name, - const std::string& defaultValue) const - { - return HttpToolbox::GetArgument(uriComponents_, name, defaultValue); - } - - std::string GetHttpHeader(const std::string& name, - const std::string& defaultValue) const - { - return HttpToolbox::GetArgument(httpHeaders_, name, defaultValue); - } - - const IHttpHandler::Arguments& GetHttpHeaders() const - { - return httpHeaders_; - } - - void ParseCookies(IHttpHandler::Arguments& result) const - { - HttpToolbox::ParseCookies(result, httpHeaders_); - } - - std::string FlattenUri() const; - - RequestOrigin GetRequestOrigin() const - { - return origin_; - } - - const char* GetRemoteIp() const - { - return remoteIp_; - } - - const char* GetUsername() const - { - return username_; - } - - virtual bool ParseJsonRequest(Json::Value& result) const = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,278 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RestApi.h" - -#include "../Logging.h" - -#include // To define "_exit()" under Windows -#include - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - class HttpHandlerVisitor : public RestApiHierarchy::IVisitor - { - private: - RestApi& api_; - RestApiOutput& output_; - RequestOrigin origin_; - const char* remoteIp_; - const char* username_; - HttpMethod method_; - const IHttpHandler::Arguments& headers_; - const IHttpHandler::Arguments& getArguments_; - const void* bodyData_; - size_t bodySize_; - - public: - HttpHandlerVisitor(RestApi& api, - RestApiOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const IHttpHandler::Arguments& headers, - const IHttpHandler::Arguments& getArguments, - const void* bodyData, - size_t bodySize) : - api_(api), - output_(output), - origin_(origin), - remoteIp_(remoteIp), - username_(username), - method_(method), - headers_(headers), - getArguments_(getArguments), - bodyData_(bodyData), - bodySize_(bodySize) - { - } - - virtual bool Visit(const RestApiHierarchy::Resource& resource, - const UriComponents& uri, - const IHttpHandler::Arguments& components, - const UriComponents& trailing) - { - if (resource.HasHandler(method_)) - { - switch (method_) - { - case HttpMethod_Get: - { - RestApiGetCall call(output_, api_, origin_, remoteIp_, username_, - headers_, components, trailing, uri, getArguments_); - resource.Handle(call); - return true; - } - - case HttpMethod_Post: - { - RestApiPostCall call(output_, api_, origin_, remoteIp_, username_, - headers_, components, trailing, uri, bodyData_, bodySize_); - resource.Handle(call); - return true; - } - - case HttpMethod_Delete: - { - RestApiDeleteCall call(output_, api_, origin_, remoteIp_, username_, - headers_, components, trailing, uri); - resource.Handle(call); - return true; - } - - case HttpMethod_Put: - { - RestApiPutCall call(output_, api_, origin_, remoteIp_, username_, - headers_, components, trailing, uri, bodyData_, bodySize_); - resource.Handle(call); - return true; - } - - default: - return false; - } - } - - return false; - } - }; - } - - - - static void AddMethod(std::string& target, - const std::string& method) - { - if (target.size() > 0) - target += "," + method; - else - target = method; - } - - static std::string MethodsToString(const std::set& methods) - { - std::string s; - - if (methods.find(HttpMethod_Get) != methods.end()) - { - AddMethod(s, "GET"); - } - - if (methods.find(HttpMethod_Post) != methods.end()) - { - AddMethod(s, "POST"); - } - - if (methods.find(HttpMethod_Put) != methods.end()) - { - AddMethod(s, "PUT"); - } - - if (methods.find(HttpMethod_Delete) != methods.end()) - { - AddMethod(s, "DELETE"); - } - - return s; - } - - - - bool RestApi::Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize) - { - RestApiOutput wrappedOutput(output, method); - -#if ORTHANC_ENABLE_PUGIXML == 1 - { - // Look if the client wishes XML answers instead of JSON - // http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z3 - Arguments::const_iterator it = headers.find("accept"); - if (it != headers.end()) - { - std::vector accepted; - Toolbox::TokenizeString(accepted, it->second, ';'); - for (size_t i = 0; i < accepted.size(); i++) - { - if (accepted[i] == MIME_XML) - { - wrappedOutput.SetConvertJsonToXml(true); - } - - if (accepted[i] == MIME_JSON) - { - wrappedOutput.SetConvertJsonToXml(false); - } - } - } - } -#endif - - Arguments compiled; - HttpToolbox::CompileGetArguments(compiled, getArguments); - - HttpHandlerVisitor visitor(*this, wrappedOutput, origin, remoteIp, username, - method, headers, compiled, bodyData, bodySize); - - if (root_.LookupResource(uri, visitor)) - { - wrappedOutput.Finalize(); - return true; - } - - std::set methods; - root_.GetAcceptedMethods(methods, uri); - - if (methods.empty()) - { - return false; // This URI is not served by this REST API - } - else - { - LOG(INFO) << "REST method " << EnumerationToString(method) - << " not allowed on: " << Toolbox::FlattenUri(uri); - - output.SendMethodNotAllowed(MethodsToString(methods)); - - return true; - } - } - - void RestApi::Register(const std::string& path, - RestApiGetCall::Handler handler) - { - root_.Register(path, handler); - } - - void RestApi::Register(const std::string& path, - RestApiPutCall::Handler handler) - { - root_.Register(path, handler); - } - - void RestApi::Register(const std::string& path, - RestApiPostCall::Handler handler) - { - root_.Register(path, handler); - } - - void RestApi::Register(const std::string& path, - RestApiDeleteCall::Handler handler) - { - root_.Register(path, handler); - } - - void RestApi::AutoListChildren(RestApiGetCall& call) - { - RestApi& context = call.GetContext(); - - Json::Value directory; - if (context.root_.GetDirectory(directory, call.GetFullUri())) - { - call.GetOutput().AnswerJson(directory); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiDeleteCall.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiDeleteCall.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiDeleteCall.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiDeleteCall.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RestApiCall.h" - -namespace Orthanc -{ - class RestApiDeleteCall : public RestApiCall - { - public: - typedef void (*Handler) (RestApiDeleteCall& call); - - RestApiDeleteCall(RestApiOutput& output, - RestApi& context, - RequestOrigin origin, - const char* remoteIp, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::Arguments& uriComponents, - const UriComponents& trailing, - const UriComponents& fullUri) : - RestApiCall(output, context, origin, remoteIp, username, - httpHeaders, uriComponents, trailing, fullUri) - { - } - - virtual bool ParseJsonRequest(Json::Value& result) const - { - result.clear(); - return true; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RestApiGetCall.h" - -namespace Orthanc -{ - bool RestApiGetCall::ParseJsonRequest(Json::Value& result) const - { - result.clear(); - - for (IHttpHandler::Arguments::const_iterator - it = getArguments_.begin(); it != getArguments_.end(); ++it) - { - result[it->first] = it->second; - } - - return true; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiGetCall.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,77 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RestApiCall.h" - -namespace Orthanc -{ - class RestApiGetCall : public RestApiCall - { - private: - const IHttpHandler::Arguments& getArguments_; - - public: - typedef void (*Handler) (RestApiGetCall& call); - - RestApiGetCall(RestApiOutput& output, - RestApi& context, - RequestOrigin origin, - const char* remoteIp, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::Arguments& uriComponents, - const UriComponents& trailing, - const UriComponents& fullUri, - const IHttpHandler::Arguments& getArguments) : - RestApiCall(output, context, origin, remoteIp, username, - httpHeaders, uriComponents, trailing, fullUri), - getArguments_(getArguments) - { - } - - std::string GetArgument(const std::string& name, - const std::string& defaultValue) const - { - return HttpToolbox::GetArgument(getArguments_, name, defaultValue); - } - - bool HasArgument(const std::string& name) const - { - return getArguments_.find(name) != getArguments_.end(); - } - - virtual bool ParseJsonRequest(Json::Value& result) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RestApiHierarchy.h" -#include "../Compatibility.h" - -#include - -namespace Orthanc -{ - class RestApi : public IHttpHandler - { - private: - RestApiHierarchy root_; - - public: - static void AutoListChildren(RestApiGetCall& call); - - virtual bool CreateChunkedRequestReader(std::unique_ptr& target, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers) - { - return false; - } - - virtual bool Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize); - - void Register(const std::string& path, - RestApiGetCall::Handler handler); - - void Register(const std::string& path, - RestApiPutCall::Handler handler); - - void Register(const std::string& path, - RestApiPostCall::Handler handler); - - void Register(const std::string& path, - RestApiDeleteCall::Handler handler); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,476 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RestApiHierarchy.h" - -#include "../OrthancException.h" - -#include -#include - -namespace Orthanc -{ - RestApiHierarchy::Resource::Resource() : - getHandler_(NULL), - postHandler_(NULL), - putHandler_(NULL), - deleteHandler_(NULL) - { - } - - - bool RestApiHierarchy::Resource::HasHandler(HttpMethod method) const - { - switch (method) - { - case HttpMethod_Get: - return getHandler_ != NULL; - - case HttpMethod_Post: - return postHandler_ != NULL; - - case HttpMethod_Put: - return putHandler_ != NULL; - - case HttpMethod_Delete: - return deleteHandler_ != NULL; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool RestApiHierarchy::Resource::IsEmpty() const - { - return (getHandler_ == NULL && - postHandler_ == NULL && - putHandler_ == NULL && - deleteHandler_ == NULL); - } - - - RestApiHierarchy& RestApiHierarchy::AddChild(Children& children, - const std::string& name) - { - Children::iterator it = children.find(name); - - if (it == children.end()) - { - // Create new child - RestApiHierarchy *child = new RestApiHierarchy; - children[name] = child; - return *child; - } - else - { - return *it->second; - } - } - - - - bool RestApiHierarchy::Resource::Handle(RestApiGetCall& call) const - { - if (getHandler_ != NULL) - { - getHandler_(call); - return true; - } - else - { - return false; - } - } - - - bool RestApiHierarchy::Resource::Handle(RestApiPutCall& call) const - { - if (putHandler_ != NULL) - { - putHandler_(call); - return true; - } - else - { - return false; - } - } - - - bool RestApiHierarchy::Resource::Handle(RestApiPostCall& call) const - { - if (postHandler_ != NULL) - { - postHandler_(call); - return true; - } - else - { - return false; - } - } - - - bool RestApiHierarchy::Resource::Handle(RestApiDeleteCall& call) const - { - if (deleteHandler_ != NULL) - { - deleteHandler_(call); - return true; - } - else - { - return false; - } - } - - - - void RestApiHierarchy::DeleteChildren(Children& children) - { - for (Children::iterator it = children.begin(); - it != children.end(); ++it) - { - delete it->second; - } - } - - - template - void RestApiHierarchy::RegisterInternal(const RestApiPath& path, - Handler handler, - size_t level) - { - if (path.GetLevelCount() == level) - { - if (path.IsUniversalTrailing()) - { - universalHandlers_.Register(handler); - } - else - { - handlers_.Register(handler); - } - } - else - { - RestApiHierarchy* child; - if (path.IsWildcardLevel(level)) - { - child = &AddChild(wildcardChildren_, path.GetWildcardName(level)); - } - else - { - child = &AddChild(children_, path.GetLevelName(level)); - } - - child->RegisterInternal(path, handler, level + 1); - } - } - - - bool RestApiHierarchy::LookupResource(IHttpHandler::Arguments& components, - const UriComponents& uri, - IVisitor& visitor, - size_t level) - { - if (uri.size() != 0 && - level > uri.size()) - { - return false; - } - - UriComponents trailing; - - // Look for an exact match on the resource of interest - if (uri.size() == 0 || - level == uri.size()) - { - if (!handlers_.IsEmpty() && - visitor.Visit(handlers_, uri, components, trailing)) - { - return true; - } - } - - - if (level < uri.size()) // A recursive call is possible - { - // Try and go down in the hierarchy, using an exact match for the child - Children::const_iterator child = children_.find(uri[level]); - if (child != children_.end()) - { - if (child->second->LookupResource(components, uri, visitor, level + 1)) - { - return true; - } - } - - // Try and go down in the hierarchy, using wildcard rules for children - for (child = wildcardChildren_.begin(); - child != wildcardChildren_.end(); ++child) - { - IHttpHandler::Arguments subComponents = components; - subComponents[child->first] = uri[level]; - - if (child->second->LookupResource(subComponents, uri, visitor, level + 1)) - { - return true; - } - } - } - - - // As a last resort, call the universal handlers, if any - if (!universalHandlers_.IsEmpty()) - { - trailing.resize(uri.size() - level); - size_t pos = 0; - for (size_t i = level; i < uri.size(); i++, pos++) - { - trailing[pos] = uri[i]; - } - - assert(pos == trailing.size()); - - if (visitor.Visit(universalHandlers_, uri, components, trailing)) - { - return true; - } - } - - return false; - } - - - bool RestApiHierarchy::CanGenerateDirectory() const - { - return (universalHandlers_.IsEmpty() && - wildcardChildren_.empty()); - } - - - bool RestApiHierarchy::GetDirectory(Json::Value& result, - const UriComponents& uri, - size_t level) - { - if (uri.size() == level) - { - if (CanGenerateDirectory()) - { - result = Json::arrayValue; - - for (Children::const_iterator it = children_.begin(); - it != children_.end(); ++it) - { - result.append(it->first); - } - - return true; - } - else - { - return false; - } - } - - Children::const_iterator child = children_.find(uri[level]); - if (child != children_.end()) - { - if (child->second->GetDirectory(result, uri, level + 1)) - { - return true; - } - } - - for (child = wildcardChildren_.begin(); - child != wildcardChildren_.end(); ++child) - { - if (child->second->GetDirectory(result, uri, level + 1)) - { - return true; - } - } - - return false; - } - - - RestApiHierarchy::~RestApiHierarchy() - { - DeleteChildren(children_); - DeleteChildren(wildcardChildren_); - } - - void RestApiHierarchy::Register(const std::string& uri, - RestApiGetCall::Handler handler) - { - RestApiPath path(uri); - RegisterInternal(path, handler, 0); - } - - void RestApiHierarchy::Register(const std::string& uri, - RestApiPutCall::Handler handler) - { - RestApiPath path(uri); - RegisterInternal(path, handler, 0); - } - - void RestApiHierarchy::Register(const std::string& uri, - RestApiPostCall::Handler handler) - { - RestApiPath path(uri); - RegisterInternal(path, handler, 0); - } - - void RestApiHierarchy::Register(const std::string& uri, - RestApiDeleteCall::Handler handler) - { - RestApiPath path(uri); - RegisterInternal(path, handler, 0); - } - - void RestApiHierarchy::CreateSiteMap(Json::Value& target) const - { - target = Json::objectValue; - - /*std::string s = " "; - if (handlers_.HasHandler(HttpMethod_Get)) - { - s += "GET "; - } - - if (handlers_.HasHandler(HttpMethod_Post)) - { - s += "POST "; - } - - if (handlers_.HasHandler(HttpMethod_Put)) - { - s += "PUT "; - } - - if (handlers_.HasHandler(HttpMethod_Delete)) - { - s += "DELETE "; - } - - target = s;*/ - - for (Children::const_iterator it = children_.begin(); - it != children_.end(); ++it) - { - it->second->CreateSiteMap(target[it->first]); - } - - for (Children::const_iterator it = wildcardChildren_.begin(); - it != wildcardChildren_.end(); ++it) - { - it->second->CreateSiteMap(target["<" + it->first + ">"]); - } - } - - - bool RestApiHierarchy::LookupResource(const UriComponents& uri, - IVisitor& visitor) - { - IHttpHandler::Arguments components; - return LookupResource(components, uri, visitor, 0); - } - - - - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - - class AcceptedMethodsVisitor : public RestApiHierarchy::IVisitor - { - private: - std::set& methods_; - - public: - AcceptedMethodsVisitor(std::set& methods) : methods_(methods) - { - } - - virtual bool Visit(const RestApiHierarchy::Resource& resource, - const UriComponents& uri, - const IHttpHandler::Arguments& components, - const UriComponents& trailing) - { - if (trailing.size() == 0) // Ignore universal handlers - { - if (resource.HasHandler(HttpMethod_Get)) - { - methods_.insert(HttpMethod_Get); - } - - if (resource.HasHandler(HttpMethod_Post)) - { - methods_.insert(HttpMethod_Post); - } - - if (resource.HasHandler(HttpMethod_Put)) - { - methods_.insert(HttpMethod_Put); - } - - if (resource.HasHandler(HttpMethod_Delete)) - { - methods_.insert(HttpMethod_Delete); - } - } - - return false; // Continue to check all the possible ways to access this URI - } - }; - } - - void RestApiHierarchy::GetAcceptedMethods(std::set& methods, - const UriComponents& uri) - { - IHttpHandler::Arguments components; - AcceptedMethodsVisitor visitor(methods); - if (LookupResource(components, uri, visitor, 0)) - { - Json::Value d; - if (GetDirectory(d, uri)) - { - methods.insert(HttpMethod_Get); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiHierarchy.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,165 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RestApiGetCall.h" -#include "RestApiPostCall.h" -#include "RestApiPutCall.h" -#include "RestApiDeleteCall.h" - -#include - -namespace Orthanc -{ - class RestApiHierarchy : public boost::noncopyable - { - public: - class Resource : public boost::noncopyable - { - private: - RestApiGetCall::Handler getHandler_; - RestApiPostCall::Handler postHandler_; - RestApiPutCall::Handler putHandler_; - RestApiDeleteCall::Handler deleteHandler_; - - public: - Resource(); - - bool HasHandler(HttpMethod method) const; - - void Register(RestApiGetCall::Handler handler) - { - getHandler_ = handler; - } - - void Register(RestApiPutCall::Handler handler) - { - putHandler_ = handler; - } - - void Register(RestApiPostCall::Handler handler) - { - postHandler_ = handler; - } - - void Register(RestApiDeleteCall::Handler handler) - { - deleteHandler_ = handler; - } - - bool IsEmpty() const; - - bool Handle(RestApiGetCall& call) const; - - bool Handle(RestApiPutCall& call) const; - - bool Handle(RestApiPostCall& call) const; - - bool Handle(RestApiDeleteCall& call) const; - }; - - - class IVisitor : public boost::noncopyable - { - public: - virtual ~IVisitor() - { - } - - virtual bool Visit(const Resource& resource, - const UriComponents& uri, - const IHttpHandler::Arguments& components, - const UriComponents& trailing) = 0; - }; - - - private: - typedef std::map Children; - - Resource handlers_; - Children children_; - Children wildcardChildren_; - Resource universalHandlers_; - - static RestApiHierarchy& AddChild(Children& children, - const std::string& name); - - static void DeleteChildren(Children& children); - - template - void RegisterInternal(const RestApiPath& path, - Handler handler, - size_t level); - - bool CanGenerateDirectory() const; - - bool LookupResource(IHttpHandler::Arguments& components, - const UriComponents& uri, - IVisitor& visitor, - size_t level); - - bool GetDirectory(Json::Value& result, - const UriComponents& uri, - size_t level); - - public: - ~RestApiHierarchy(); - - void Register(const std::string& uri, - RestApiGetCall::Handler handler); - - void Register(const std::string& uri, - RestApiPutCall::Handler handler); - - void Register(const std::string& uri, - RestApiPostCall::Handler handler); - - void Register(const std::string& uri, - RestApiDeleteCall::Handler handler); - - void CreateSiteMap(Json::Value& target) const; - - bool GetDirectory(Json::Value& result, - const UriComponents& uri) - { - return GetDirectory(result, uri, 0); - } - - bool LookupResource(const UriComponents& uri, - IVisitor& visitor); - - void GetAcceptedMethods(std::set& methods, - const UriComponents& uri); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,222 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RestApiOutput.h" - -#include "../Logging.h" -#include "../OrthancException.h" -#include "../Toolbox.h" - -#include - - -namespace Orthanc -{ - RestApiOutput::RestApiOutput(HttpOutput& output, - HttpMethod method) : - output_(output), - method_(method), - convertJsonToXml_(false) - { - alreadySent_ = false; - } - - RestApiOutput::~RestApiOutput() - { - } - - void RestApiOutput::Finalize() - { - if (!alreadySent_) - { - if (method_ == HttpMethod_Post) - { - output_.SendStatus(HttpStatus_400_BadRequest); - } - else - { - output_.SendStatus(HttpStatus_404_NotFound); - } - } - } - - void RestApiOutput::CheckStatus() - { - if (alreadySent_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void RestApiOutput::AnswerStream(IHttpStreamAnswer& stream) - { - CheckStatus(); - output_.Answer(stream); - alreadySent_ = true; - } - - void RestApiOutput::AnswerJson(const Json::Value& value) - { - CheckStatus(); - - if (convertJsonToXml_) - { -#if ORTHANC_ENABLE_PUGIXML == 1 - std::string s; - Toolbox::JsonToXml(s, value); - - output_.SetContentType(MIME_XML_UTF8); - output_.Answer(s); -#else - throw OrthancException(ErrorCode_InternalError, - "Orthanc was compiled without XML support"); -#endif - } - else - { - Json::StyledWriter writer; - std::string s = writer.write(value); - - output_.SetContentType(MIME_JSON_UTF8); - output_.Answer(s); - } - - alreadySent_ = true; - } - - void RestApiOutput::AnswerBuffer(const std::string& buffer, - MimeType contentType) - { - AnswerBuffer(buffer.size() == 0 ? NULL : buffer.c_str(), - buffer.size(), contentType); - } - - void RestApiOutput::AnswerBuffer(const void* buffer, - size_t length, - MimeType contentType) - { - CheckStatus(); - - if (convertJsonToXml_ && - contentType == MimeType_Json) - { - Json::Value json; - Json::Reader reader; - if (reader.parse(reinterpret_cast(buffer), - reinterpret_cast(buffer) + length, json)) - { - AnswerJson(json); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "The REST API tries and answers with an invalid JSON file"); - } - } - else - { - output_.SetContentType(contentType); - output_.Answer(buffer, length); - alreadySent_ = true; - } - } - - void RestApiOutput::Redirect(const std::string& path) - { - CheckStatus(); - output_.Redirect(path); - alreadySent_ = true; - } - - void RestApiOutput::SignalErrorInternal(HttpStatus status, - const char* message, - size_t messageSize) - { - if (status != HttpStatus_400_BadRequest && - status != HttpStatus_403_Forbidden && - status != HttpStatus_500_InternalServerError && - status != HttpStatus_415_UnsupportedMediaType) - { - throw OrthancException(ErrorCode_BadHttpStatusInRest); - } - - CheckStatus(); - output_.SendStatus(status, message, messageSize); - alreadySent_ = true; - } - - void RestApiOutput::SignalError(HttpStatus status) - { - SignalErrorInternal(status, NULL, 0); - } - - void RestApiOutput::SignalError(HttpStatus status, - const std::string& message) - { - SignalErrorInternal(status, message.c_str(), message.size()); - } - - void RestApiOutput::SetCookie(const std::string& name, - const std::string& value, - unsigned int maxAge) - { - if (name.find(";") != std::string::npos || - name.find(" ") != std::string::npos || - value.find(";") != std::string::npos || - value.find(" ") != std::string::npos) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - CheckStatus(); - - std::string v = value + ";path=/"; - - if (maxAge != 0) - { - v += ";max-age=" + boost::lexical_cast(maxAge); - } - - output_.SetCookie(name, v); - } - - void RestApiOutput::ResetCookie(const std::string& name) - { - // This marks the cookie to be deleted by the browser in 1 second, - // and before it actually gets deleted, its value is set to the - // empty string - SetCookie(name, "", 1); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiOutput.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,99 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../HttpServer/HttpOutput.h" -#include "../HttpServer/HttpFileSender.h" - -#include - -namespace Orthanc -{ - class RestApiOutput - { - private: - HttpOutput& output_; - HttpMethod method_; - bool alreadySent_; - bool convertJsonToXml_; - - void CheckStatus(); - - void SignalErrorInternal(HttpStatus status, - const char* message, - size_t messageSize); - - public: - RestApiOutput(HttpOutput& output, - HttpMethod method); - - ~RestApiOutput(); - - void SetConvertJsonToXml(bool convert) - { - convertJsonToXml_ = convert; - } - - bool IsConvertJsonToXml() const - { - return convertJsonToXml_; - } - - void AnswerStream(IHttpStreamAnswer& stream); - - void AnswerJson(const Json::Value& value); - - void AnswerBuffer(const std::string& buffer, - MimeType contentType); - - void AnswerBuffer(const void* buffer, - size_t length, - MimeType contentType); - - void SignalError(HttpStatus status); - - void SignalError(HttpStatus status, - const std::string& message); - - void Redirect(const std::string& path); - - void SetCookie(const std::string& name, - const std::string& value, - unsigned int maxAge = 0); - - void ResetCookie(const std::string& name); - - void Finalize(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeaders.h" -#include "RestApiPath.h" - -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - RestApiPath::RestApiPath(const std::string& uri) - { - Toolbox::SplitUriComponents(uri_, uri); - - if (uri_.size() == 0) - { - hasTrailing_ = false; - return; - } - - if (uri_.back() == "*") - { - hasTrailing_ = true; - uri_.pop_back(); - } - else - { - hasTrailing_ = false; - } - - components_.resize(uri_.size()); - for (size_t i = 0; i < uri_.size(); i++) - { - size_t s = uri_[i].size(); - assert(s > 0); - - if (uri_[i][0] == '{' && - uri_[i][s - 1] == '}') - { - components_[i] = uri_[i].substr(1, s - 2); - uri_[i] = ""; - } - else - { - components_[i] = ""; - } - } - } - - bool RestApiPath::Match(IHttpHandler::Arguments& components, - UriComponents& trailing, - const std::string& uriRaw) const - { - UriComponents uri; - Toolbox::SplitUriComponents(uri, uriRaw); - return Match(components, trailing, uri); - } - - bool RestApiPath::Match(IHttpHandler::Arguments& components, - UriComponents& trailing, - const UriComponents& uri) const - { - assert(uri_.size() == components_.size()); - - if (uri.size() < uri_.size()) - { - return false; - } - - if (!hasTrailing_ && uri.size() > uri_.size()) - { - return false; - } - - components.clear(); - trailing.clear(); - - assert(uri_.size() <= uri.size()); - for (size_t i = 0; i < uri_.size(); i++) - { - if (components_[i].size() == 0) - { - // This URI component is not a free parameter - if (uri_[i] != uri[i]) - { - return false; - } - } - else - { - // This URI component is a free parameter - components[components_[i]] = uri[i]; - } - } - - if (hasTrailing_) - { - trailing.assign(uri.begin() + uri_.size(), uri.end()); - } - - return true; - } - - - bool RestApiPath::Match(const UriComponents& uri) const - { - IHttpHandler::Arguments components; - UriComponents trailing; - return Match(components, trailing, uri); - } - - - bool RestApiPath::IsWildcardLevel(size_t level) const - { - assert(uri_.size() == components_.size()); - - if (level >= uri_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - return uri_[level].length() == 0; - } - - const std::string& RestApiPath::GetWildcardName(size_t level) const - { - assert(uri_.size() == components_.size()); - - if (!IsWildcardLevel(level)) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - return components_[level]; - } - - const std::string& RestApiPath::GetLevelName(size_t level) const - { - assert(uri_.size() == components_.size()); - - if (IsWildcardLevel(level)) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - return uri_[level]; - } -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPath.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Toolbox.h" -#include "../HttpServer/IHttpHandler.h" - -#include - -namespace Orthanc -{ - class RestApiPath - { - private: - UriComponents uri_; - bool hasTrailing_; - std::vector components_; - - public: - RestApiPath(const std::string& uri); - - // This version is slower - bool Match(IHttpHandler::Arguments& components, - UriComponents& trailing, - const std::string& uriRaw) const; - - bool Match(IHttpHandler::Arguments& components, - UriComponents& trailing, - const UriComponents& uri) const; - - bool Match(const UriComponents& uri) const; - - size_t GetLevelCount() const - { - return uri_.size(); - } - - bool IsWildcardLevel(size_t level) const; - - bool IsUniversalTrailing() const - { - return hasTrailing_; - } - - const std::string& GetWildcardName(size_t level) const; - - const std::string& GetLevelName(size_t level) const; - - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPostCall.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPostCall.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPostCall.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPostCall.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RestApiCall.h" - -namespace Orthanc -{ - class RestApiPostCall : public RestApiCall - { - private: - const void* bodyData_; - size_t bodySize_; - - public: - typedef void (*Handler) (RestApiPostCall& call); - - RestApiPostCall(RestApiOutput& output, - RestApi& context, - RequestOrigin origin, - const char* remoteIp, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::Arguments& uriComponents, - const UriComponents& trailing, - const UriComponents& fullUri, - const void* bodyData, - size_t bodySize) : - RestApiCall(output, context, origin, remoteIp, username, - httpHeaders, uriComponents, trailing, fullUri), - bodyData_(bodyData), - bodySize_(bodySize) - { - } - - const void* GetBodyData() const - { - return bodyData_; - } - - size_t GetBodySize() const - { - return bodySize_; - } - - void BodyToString(std::string& result) const - { - result.assign(reinterpret_cast(bodyData_), bodySize_); - } - - virtual bool ParseJsonRequest(Json::Value& result) const - { - return ParseJsonRequestInternal(result, reinterpret_cast(bodyData_), bodySize_); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPutCall.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPutCall.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPutCall.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/RestApi/RestApiPutCall.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "RestApiCall.h" - -namespace Orthanc -{ - class RestApiPutCall : public RestApiCall - { - private: - const void* bodyData_; - size_t bodySize_; - - public: - typedef void (*Handler) (RestApiPutCall& call); - - RestApiPutCall(RestApiOutput& output, - RestApi& context, - RequestOrigin origin, - const char* remoteIp, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::Arguments& uriComponents, - const UriComponents& trailing, - const UriComponents& fullUri, - const void* bodyData, - size_t bodySize) : - RestApiCall(output, context, origin, remoteIp, username, - httpHeaders, uriComponents, trailing, fullUri), - bodyData_(bodyData), - bodySize_(bodySize) - { - } - - const void* GetBodyData() const - { - return bodyData_; - } - - size_t GetBodySize() const - { - return bodySize_; - } - - void BodyToString(std::string& result) const - { - result.assign(reinterpret_cast(bodyData_), bodySize_); - } - - virtual bool ParseJsonRequest(Json::Value& result) const - { - return ParseJsonRequestInternal(result, reinterpret_cast(bodyData_), bodySize_); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,447 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "SerializationToolbox.h" - -#include "OrthancException.h" - -#if ORTHANC_ENABLE_DCMTK == 1 -# include "DicomParsing/FromDcmtkBridge.h" -#endif - -namespace Orthanc -{ - namespace SerializationToolbox - { - static bool ParseTagInternal(DicomTag& tag, - const char* name) - { -#if ORTHANC_ENABLE_DCMTK == 1 - try - { - tag = FromDcmtkBridge::ParseTag(name); - return true; - } - catch (OrthancException&) - { - return false; - } -#else - return DicomTag::ParseHexadecimal(tag, name); -#endif - } - - - std::string ReadString(const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "String value expected in field: " + field); - } - else - { - return value[field.c_str()].asString(); - } - } - - - int ReadInteger(const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - (value[field.c_str()].type() != Json::intValue && - value[field.c_str()].type() != Json::uintValue)) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Integer value expected in field: " + field); - } - else - { - return value[field.c_str()].asInt(); - } - } - - - int ReadInteger(const Json::Value& value, - const std::string& field, - int defaultValue) - { - if (value.isMember(field.c_str())) - { - return ReadInteger(value, field); - } - else - { - return defaultValue; - } - } - - - unsigned int ReadUnsignedInteger(const Json::Value& value, - const std::string& field) - { - int tmp = ReadInteger(value, field); - - if (tmp < 0) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Unsigned integer value expected in field: " + field); - } - else - { - return static_cast(tmp); - } - } - - - bool ReadBoolean(const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::booleanValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Boolean value expected in field: " + field); - } - else - { - return value[field.c_str()].asBool(); - } - } - - - void ReadArrayOfStrings(std::vector& target, - const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "List of strings expected in field: " + field); - } - - const Json::Value& arr = value[field.c_str()]; - - target.resize(arr.size()); - - for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++) - { - if (arr[i].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "List of strings expected in field: " + field); - } - else - { - target[i] = arr[i].asString(); - } - } - } - - - void ReadListOfStrings(std::list& target, - const Json::Value& value, - const std::string& field) - { - std::vector tmp; - ReadArrayOfStrings(tmp, value, field); - - target.clear(); - for (size_t i = 0; i < tmp.size(); i++) - { - target.push_back(tmp[i]); - } - } - - - void ReadSetOfStrings(std::set& target, - const Json::Value& value, - const std::string& field) - { - std::vector tmp; - ReadArrayOfStrings(tmp, value, field); - - target.clear(); - for (size_t i = 0; i < tmp.size(); i++) - { - target.insert(tmp[i]); - } - } - - - void ReadSetOfTags(std::set& target, - const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Set of DICOM tags expected in field: " + field); - } - - const Json::Value& arr = value[field.c_str()]; - - target.clear(); - - for (Json::Value::ArrayIndex i = 0; i < arr.size(); i++) - { - DicomTag tag(0, 0); - - if (arr[i].type() != Json::stringValue || - !ParseTagInternal(tag, arr[i].asCString())) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Set of DICOM tags expected in field: " + field); - } - else - { - target.insert(tag); - } - } - } - - - void ReadMapOfStrings(std::map& target, - const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Associative array of strings to strings expected in field: " + field); - } - - const Json::Value& source = value[field.c_str()]; - - target.clear(); - - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& tmp = source[members[i]]; - - if (tmp.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Associative array of string to strings expected in field: " + field); - } - else - { - target[members[i]] = tmp.asString(); - } - } - } - - - void ReadMapOfTags(std::map& target, - const Json::Value& value, - const std::string& field) - { - if (value.type() != Json::objectValue || - !value.isMember(field.c_str()) || - value[field.c_str()].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Associative array of DICOM tags to strings expected in field: " + field); - } - - const Json::Value& source = value[field.c_str()]; - - target.clear(); - - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& tmp = source[members[i]]; - - DicomTag tag(0, 0); - - if (!ParseTagInternal(tag, members[i].c_str()) || - tmp.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Associative array of DICOM tags to strings expected in field: " + field); - } - else - { - target[tag] = tmp.asString(); - } - } - } - - - void WriteArrayOfStrings(Json::Value& target, - const std::vector& values, - const std::string& field) - { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value& value = target[field]; - - value = Json::arrayValue; - for (size_t i = 0; i < values.size(); i++) - { - value.append(values[i]); - } - } - - - void WriteListOfStrings(Json::Value& target, - const std::list& values, - const std::string& field) - { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value& value = target[field]; - - value = Json::arrayValue; - - for (std::list::const_iterator it = values.begin(); - it != values.end(); ++it) - { - value.append(*it); - } - } - - - void WriteSetOfStrings(Json::Value& target, - const std::set& values, - const std::string& field) - { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value& value = target[field]; - - value = Json::arrayValue; - - for (std::set::const_iterator it = values.begin(); - it != values.end(); ++it) - { - value.append(*it); - } - } - - - void WriteSetOfTags(Json::Value& target, - const std::set& tags, - const std::string& field) - { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value& value = target[field]; - - value = Json::arrayValue; - - for (std::set::const_iterator it = tags.begin(); - it != tags.end(); ++it) - { - value.append(it->Format()); - } - } - - - void WriteMapOfStrings(Json::Value& target, - const std::map& values, - const std::string& field) - { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value& value = target[field]; - - value = Json::objectValue; - - for (std::map::const_iterator - it = values.begin(); it != values.end(); ++it) - { - value[it->first] = it->second; - } - } - - - void WriteMapOfTags(Json::Value& target, - const std::map& values, - const std::string& field) - { - if (target.type() != Json::objectValue || - target.isMember(field.c_str())) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value& value = target[field]; - - value = Json::objectValue; - - for (std::map::const_iterator - it = values.begin(); it != values.end(); ++it) - { - value[it->first.Format()] = it->second; - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SerializationToolbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomFormat/DicomTag.h" - -#include -#include -#include - -namespace Orthanc -{ - namespace SerializationToolbox - { - std::string ReadString(const Json::Value& value, - const std::string& field); - - int ReadInteger(const Json::Value& value, - const std::string& field); - - int ReadInteger(const Json::Value& value, - const std::string& field, - int defaultValue); - - unsigned int ReadUnsignedInteger(const Json::Value& value, - const std::string& field); - - bool ReadBoolean(const Json::Value& value, - const std::string& field); - - void ReadArrayOfStrings(std::vector& target, - const Json::Value& value, - const std::string& field); - - void ReadListOfStrings(std::list& target, - const Json::Value& value, - const std::string& field); - - void ReadSetOfStrings(std::set& target, - const Json::Value& value, - const std::string& field); - - void ReadSetOfTags(std::set& target, - const Json::Value& value, - const std::string& field); - - void ReadMapOfStrings(std::map& values, - const Json::Value& target, - const std::string& field); - - void ReadMapOfTags(std::map& values, - const Json::Value& target, - const std::string& field); - - void WriteArrayOfStrings(Json::Value& target, - const std::vector& values, - const std::string& field); - - void WriteListOfStrings(Json::Value& target, - const std::list& values, - const std::string& field); - - void WriteSetOfStrings(Json::Value& target, - const std::set& values, - const std::string& field); - - void WriteSetOfTags(Json::Value& target, - const std::set& tags, - const std::string& field); - - void WriteMapOfStrings(Json::Value& target, - const std::map& values, - const std::string& field); - - void WriteMapOfTags(Json::Value& target, - const std::map& values, - const std::string& field); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "SharedLibrary.h" - -#include "Logging.h" -#include "OrthancException.h" - -#include - -#if defined(_WIN32) -#include -#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#else -#error Support your platform here -#endif - -namespace Orthanc -{ - SharedLibrary::SharedLibrary(const std::string& path) : - path_(path), - handle_(NULL) - { -#if defined(_WIN32) - handle_ = ::LoadLibraryA(path_.c_str()); - if (handle_ == NULL) - { - LOG(ERROR) << "LoadLibrary(" << path_ << ") failed: Error " << ::GetLastError(); - throw OrthancException(ErrorCode_SharedLibrary); - } - -#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) - - /** - * "RTLD_LOCAL" is the default, and is only present to be - * explicit. "RTLD_DEEPBIND" was added in Orthanc 1.6.0, in order - * to avoid crashes while loading plugins from the LSB binaries of - * the Orthanc core. - * - * BUT this had no effect, and this results in a crash if loading - * the Python 2.7 plugin => We disabled it again in Orthanc 1.6.1. - **/ - -#if 0 // && defined(RTLD_DEEPBIND) // This is a GNU extension - // Disabled in Orthanc 1.6.1 - handle_ = ::dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND); -#else - handle_ = ::dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL); -#endif - - if (handle_ == NULL) - { - std::string explanation; - const char *tmp = ::dlerror(); - if (tmp) - { - explanation = ": Error " + std::string(tmp); - } - - LOG(ERROR) << "dlopen(" << path_ << ") failed" << explanation; - throw OrthancException(ErrorCode_SharedLibrary); - } - -#else -#error Support your platform here -#endif - } - - SharedLibrary::~SharedLibrary() - { - if (handle_) - { -#if defined(_WIN32) - ::FreeLibrary((HMODULE)handle_); -#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) - ::dlclose(handle_); -#else -#error Support your platform here -#endif - } - } - - - SharedLibrary::FunctionPointer SharedLibrary::GetFunctionInternal(const std::string& name) - { - if (!handle_) - { - throw OrthancException(ErrorCode_InternalError); - } - -#if defined(_WIN32) - return ::GetProcAddress((HMODULE)handle_, name.c_str()); -#elif defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) - return ::dlsym(handle_, name.c_str()); -#else -#error Support your platform here -#endif - } - - - SharedLibrary::FunctionPointer SharedLibrary::GetFunction(const std::string& name) - { - SharedLibrary::FunctionPointer result = GetFunctionInternal(name); - - if (result == NULL) - { - throw OrthancException( - ErrorCode_SharedLibrary, - "Shared library does not expose function \"" + name + "\""); - } - else - { - return result; - } - } - - - bool SharedLibrary::HasFunction(const std::string& name) - { - return GetFunctionInternal(name) != NULL; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SharedLibrary.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The namespace SystemToolbox cannot be used in sandboxed environments -#endif - -#if defined(_WIN32) -#include -#endif - -#include -#include - -namespace Orthanc -{ - class SharedLibrary : public boost::noncopyable - { - public: -#if defined(_WIN32) - typedef FARPROC FunctionPointer; -#else - typedef void* FunctionPointer; -#endif - - private: - std::string path_; - void *handle_; - - FunctionPointer GetFunctionInternal(const std::string& name); - - public: - explicit SharedLibrary(const std::string& path); - - ~SharedLibrary(); - - const std::string& GetPath() const - { - return path_; - } - - bool HasFunction(const std::string& name); - - FunctionPointer GetFunction(const std::string& name); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,399 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "Connection.h" -#include "OrthancSQLiteException.h" - -#include -#include -#include - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../Logging.h" -#endif - -#include "sqlite3.h" - - -namespace Orthanc -{ - namespace SQLite - { - Connection::Connection() : - db_(NULL), - transactionNesting_(0), - needsRollback_(false) - { - } - - - Connection::~Connection() - { - Close(); - } - - - void Connection::CheckIsOpen() const - { - if (!db_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteNotOpened); - } - } - - void Connection::Open(const std::string& path) - { - if (db_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteAlreadyOpened); - } - - int err = sqlite3_open(path.c_str(), &db_); - if (err != SQLITE_OK) - { - Close(); - db_ = NULL; - throw OrthancSQLiteException(ErrorCode_SQLiteCannotOpen); - } - - // Execute PRAGMAs at this point - // http://www.sqlite.org/pragma.html - Execute("PRAGMA FOREIGN_KEYS=ON;"); - Execute("PRAGMA RECURSIVE_TRIGGERS=ON;"); - } - - void Connection::OpenInMemory() - { - Open(":memory:"); - } - - void Connection::Close() - { - ClearCache(); - - if (db_) - { - sqlite3_close(db_); - db_ = NULL; - } - } - - void Connection::ClearCache() - { - for (CachedStatements::iterator - it = cachedStatements_.begin(); - it != cachedStatements_.end(); ++it) - { - delete it->second; - } - - cachedStatements_.clear(); - } - - - StatementReference& Connection::GetCachedStatement(const StatementId& id, - const char* sql) - { - CachedStatements::iterator i = cachedStatements_.find(id); - if (i != cachedStatements_.end()) - { - if (i->second->GetReferenceCount() >= 1) - { - throw OrthancSQLiteException(ErrorCode_SQLiteStatementAlreadyUsed); - } - - return *i->second; - } - else - { - StatementReference* statement = new StatementReference(db_, sql); - cachedStatements_[id] = statement; - return *statement; - } - } - - - bool Connection::Execute(const char* sql) - { -#if ORTHANC_SQLITE_STANDALONE != 1 - VLOG(1) << "SQLite::Connection::Execute " << sql; -#endif - - CheckIsOpen(); - - int error = sqlite3_exec(db_, sql, NULL, NULL, NULL); - if (error == SQLITE_ERROR) - { -#if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "SQLite execute error: " << sqlite3_errmsg(db_) - << " (" << sqlite3_extended_errcode(db_) << ")"; -#endif - - throw OrthancSQLiteException(ErrorCode_SQLiteExecute); - } - else - { - return error == SQLITE_OK; - } - } - - int Connection::ExecuteAndReturnErrorCode(const char* sql) - { - CheckIsOpen(); - return sqlite3_exec(db_, sql, NULL, NULL, NULL); - } - - // Info querying ------------------------------------------------------------- - - bool Connection::IsSQLValid(const char* sql) - { - sqlite3_stmt* stmt = NULL; - if (sqlite3_prepare_v2(db_, sql, -1, &stmt, NULL) != SQLITE_OK) - return false; - - sqlite3_finalize(stmt); - return true; - } - - bool Connection::DoesTableOrIndexExist(const char* name, - const char* type) const - { - // Our SQL is non-mutating, so this cast is OK. - Statement statement(const_cast(*this), - "SELECT name FROM sqlite_master WHERE type=? AND name=?"); - statement.BindString(0, type); - statement.BindString(1, name); - return statement.Step(); // Table exists if any row was returned. - } - - bool Connection::DoesTableExist(const char* table_name) const - { - return DoesTableOrIndexExist(table_name, "table"); - } - - bool Connection::DoesIndexExist(const char* index_name) const - { - return DoesTableOrIndexExist(index_name, "index"); - } - - bool Connection::DoesColumnExist(const char* table_name, const char* column_name) const - { - std::string sql("PRAGMA TABLE_INFO("); - sql.append(table_name); - sql.append(")"); - - // Our SQL is non-mutating, so this cast is OK. - Statement statement(const_cast(*this), sql.c_str()); - - while (statement.Step()) { - if (!statement.ColumnString(1).compare(column_name)) - return true; - } - return false; - } - - int64_t Connection::GetLastInsertRowId() const - { - return sqlite3_last_insert_rowid(db_); - } - - int Connection::GetLastChangeCount() const - { - return sqlite3_changes(db_); - } - - int Connection::GetErrorCode() const - { - return sqlite3_errcode(db_); - } - - int Connection::GetLastErrno() const - { - int err = 0; - if (SQLITE_OK != sqlite3_file_control(db_, NULL, SQLITE_LAST_ERRNO, &err)) - return -2; - - return err; - } - - const char* Connection::GetErrorMessage() const - { - return sqlite3_errmsg(db_); - } - - - bool Connection::BeginTransaction() - { - if (needsRollback_) - { - assert(transactionNesting_ > 0); - - // When we're going to rollback, fail on this begin and don't actually - // mark us as entering the nested transaction. - return false; - } - - bool success = true; - if (!transactionNesting_) - { - needsRollback_ = false; - - Statement begin(*this, SQLITE_FROM_HERE, "BEGIN TRANSACTION"); - if (!begin.Run()) - return false; - } - transactionNesting_++; - return success; - } - - void Connection::RollbackTransaction() - { - if (!transactionNesting_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction); - } - - transactionNesting_--; - - if (transactionNesting_ > 0) - { - // Mark the outermost transaction as needing rollback. - needsRollback_ = true; - return; - } - - DoRollback(); - } - - bool Connection::CommitTransaction() - { - if (!transactionNesting_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteCommitWithoutTransaction); - } - transactionNesting_--; - - if (transactionNesting_ > 0) - { - // Mark any nested transactions as failing after we've already got one. - return !needsRollback_; - } - - if (needsRollback_) - { - DoRollback(); - return false; - } - - Statement commit(*this, SQLITE_FROM_HERE, "COMMIT"); - return commit.Run(); - } - - void Connection::DoRollback() - { - Statement rollback(*this, SQLITE_FROM_HERE, "ROLLBACK"); - rollback.Run(); - needsRollback_ = false; - } - - - - - - - static void ScalarFunctionCaller(sqlite3_context* rawContext, - int argc, - sqlite3_value** argv) - { - FunctionContext context(rawContext, argc, argv); - - void* payload = sqlite3_user_data(rawContext); - assert(payload != NULL); - - IScalarFunction& func = *reinterpret_cast(payload); - func.Compute(context); - } - - - static void ScalarFunctionDestroyer(void* payload) - { - assert(payload != NULL); - delete reinterpret_cast(payload); - } - - - IScalarFunction* Connection::Register(IScalarFunction* func) - { - int err = sqlite3_create_function_v2(db_, - func->GetName(), - func->GetCardinality(), - SQLITE_UTF8, - func, - ScalarFunctionCaller, - NULL, - NULL, - ScalarFunctionDestroyer); - - if (err != SQLITE_OK) - { - delete func; - throw OrthancSQLiteException(ErrorCode_SQLiteRegisterFunction); - } - - return func; - } - - - void Connection::FlushToDisk() - { -#if ORTHANC_SQLITE_STANDALONE != 1 - VLOG(1) << "SQLite::Connection::FlushToDisk"; -#endif - - int err = sqlite3_wal_checkpoint(db_, NULL); - - if (err != SQLITE_OK) - { - throw OrthancSQLiteException(ErrorCode_SQLiteFlush); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Connection.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,175 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "Statement.h" -#include "IScalarFunction.h" -#include "SQLiteTypes.h" - -#include -#include - -#define SQLITE_FROM_HERE ::Orthanc::SQLite::StatementId(__FILE__, __LINE__) - -namespace Orthanc -{ - namespace SQLite - { - class Connection : NonCopyable - { - friend class Statement; - friend class Transaction; - - private: - // All cached statements. Keeping a reference to these statements means that - // they'll remain active. - typedef std::map CachedStatements; - CachedStatements cachedStatements_; - - // The actual sqlite database. Will be NULL before Init has been called or if - // Init resulted in an error. - sqlite3* db_; - - // Number of currently-nested transactions. - int transactionNesting_; - - // True if any of the currently nested transactions have been rolled back. - // When we get to the outermost transaction, this will determine if we do - // a rollback instead of a commit. - bool needsRollback_; - - void ClearCache(); - - void CheckIsOpen() const; - - sqlite3* GetWrappedObject() - { - return db_; - } - - StatementReference& GetCachedStatement(const StatementId& id, - const char* sql); - - bool DoesTableOrIndexExist(const char* name, - const char* type) const; - - void DoRollback(); - - public: - // The database is opened by calling Open[InMemory](). Any uncommitted - // transactions will be rolled back when this object is deleted. - Connection(); - ~Connection(); - - void Open(const std::string& path); - - void OpenInMemory(); - - void Close(); - - bool Execute(const char* sql); - - bool Execute(const std::string& sql) - { - return Execute(sql.c_str()); - } - - void FlushToDisk(); - - IScalarFunction* Register(IScalarFunction* func); // Takes the ownership of the function - - // Info querying ------------------------------------------------------------- - - // Used to check a |sql| statement for syntactic validity. If the - // statement is valid SQL, returns true. - bool IsSQLValid(const char* sql); - - // Returns true if the given table exists. - bool DoesTableExist(const char* table_name) const; - - // Returns true if the given index exists. - bool DoesIndexExist(const char* index_name) const; - - // Returns true if a column with the given name exists in the given table. - bool DoesColumnExist(const char* table_name, const char* column_name) const; - - // Returns sqlite's internal ID for the last inserted row. Valid only - // immediately after an insert. - int64_t GetLastInsertRowId() const; - - // Returns sqlite's count of the number of rows modified by the last - // statement executed. Will be 0 if no statement has executed or the database - // is closed. - int GetLastChangeCount() const; - - // Errors -------------------------------------------------------------------- - - // Returns the error code associated with the last sqlite operation. - int GetErrorCode() const; - - // Returns the errno associated with GetErrorCode(). See - // SQLITE_LAST_ERRNO in SQLite documentation. - int GetLastErrno() const; - - // Returns a pointer to a statically allocated string associated with the - // last sqlite operation. - const char* GetErrorMessage() const; - - - // Diagnostics (for unit tests) ---------------------------------------------- - - int ExecuteAndReturnErrorCode(const char* sql); - - bool HasCachedStatement(const StatementId& id) const - { - return cachedStatements_.find(id) != cachedStatements_.end(); - } - - int GetTransactionNesting() const - { - return transactionNesting_; - } - - // Transactions -------------------------------------------------------------- - - bool BeginTransaction(); - void RollbackTransaction(); - bool CommitTransaction(); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "FunctionContext.h" -#include "OrthancSQLiteException.h" - -#include - -#include "sqlite3.h" - -namespace Orthanc -{ - namespace SQLite - { - FunctionContext::FunctionContext(struct sqlite3_context* context, - int argc, - Internals::SQLiteValue** argv) - { - assert(context != NULL); - assert(argc >= 0); - assert(argv != NULL); - - context_ = context; - argc_ = static_cast(argc); - argv_ = argv; - } - - void FunctionContext::CheckIndex(unsigned int index) const - { - if (index >= argc_) - { - throw OrthancSQLiteException(ErrorCode_ParameterOutOfRange); - } - } - - ColumnType FunctionContext::GetColumnType(unsigned int index) const - { - CheckIndex(index); - return static_cast(sqlite3_value_type(argv_[index])); - } - - int FunctionContext::GetIntValue(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_int(argv_[index]); - } - - int64_t FunctionContext::GetInt64Value(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_int64(argv_[index]); - } - - double FunctionContext::GetDoubleValue(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_double(argv_[index]); - } - - std::string FunctionContext::GetStringValue(unsigned int index) const - { - CheckIndex(index); - return std::string(reinterpret_cast(sqlite3_value_text(argv_[index]))); - } - - bool FunctionContext::IsNullValue(unsigned int index) const - { - CheckIndex(index); - return sqlite3_value_type(argv_[index]) == SQLITE_NULL; - } - - void FunctionContext::SetNullResult() - { - sqlite3_result_null(context_); - } - - void FunctionContext::SetIntResult(int value) - { - sqlite3_result_int(context_, value); - } - - void FunctionContext::SetDoubleResult(double value) - { - sqlite3_result_double(context_, value); - } - - void FunctionContext::SetStringResult(const std::string& str) - { - sqlite3_result_text(context_, str.data(), static_cast(str.size()), SQLITE_TRANSIENT); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/FunctionContext.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "Statement.h" - -namespace Orthanc -{ - namespace SQLite - { - class FunctionContext : public NonCopyable - { - friend class Connection; - - private: - struct sqlite3_context* context_; - unsigned int argc_; - Internals::SQLiteValue** argv_; - - void CheckIndex(unsigned int index) const; - - public: - FunctionContext(struct sqlite3_context* context, - int argc, - Internals::SQLiteValue** argv); - - ColumnType GetColumnType(unsigned int index) const; - - unsigned int GetParameterCount() const - { - return argc_; - } - - int GetIntValue(unsigned int index) const; - - int64_t GetInt64Value(unsigned int index) const; - - double GetDoubleValue(unsigned int index) const; - - std::string GetStringValue(unsigned int index) const; - - bool IsNullValue(unsigned int index) const; - - void SetNullResult(); - - void SetIntResult(int value); - - void SetDoubleResult(double value); - - void SetStringResult(const std::string& str); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/IScalarFunction.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/IScalarFunction.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/IScalarFunction.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/IScalarFunction.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "NonCopyable.h" -#include "FunctionContext.h" - -namespace Orthanc -{ - namespace SQLite - { - class IScalarFunction : public NonCopyable - { - public: - virtual ~IScalarFunction() - { - } - - virtual const char* GetName() const = 0; - - virtual unsigned int GetCardinality() const = 0; - - virtual void Compute(FunctionContext& context) = 0; - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/ITransaction.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/ITransaction.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/ITransaction.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/ITransaction.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "NonCopyable.h" - -namespace Orthanc -{ - namespace SQLite - { - class ITransaction : public NonCopyable - { - public: - virtual ~ITransaction() - { - } - - // Begins the transaction. This uses the default sqlite "deferred" transaction - // type, which means that the DB lock is lazily acquired the next time the - // database is accessed, not in the begin transaction command. - virtual void Begin() = 0; - - // Rolls back the transaction. This will happen automatically if you do - // nothing when the transaction goes out of scope. - virtual void Rollback() = 0; - - // Commits the transaction, returning true on success. - virtual void Commit() = 0; - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/NonCopyable.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/NonCopyable.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/NonCopyable.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/NonCopyable.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -namespace Orthanc -{ - namespace SQLite - { - // This class mimics "boost::noncopyable" - class NonCopyable - { - private: - NonCopyable(const NonCopyable&); - - NonCopyable& operator= (const NonCopyable&); - - protected: - NonCopyable() - { - } - - ~NonCopyable() - { - } - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/OrthancSQLiteException.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/OrthancSQLiteException.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/OrthancSQLiteException.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/OrthancSQLiteException.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,154 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - - -#if ORTHANC_ENABLE_SQLITE != 1 -# error Macro ORTHANC_ENABLE_SQLITE must be set to 1 to use SQLite -#endif - - -#if ORTHANC_SQLITE_STANDALONE == 1 -#include - -namespace Orthanc -{ - namespace SQLite - { - // Auto-generated by "Resources/GenerateErrorCodes.py" - enum ErrorCode - { - ErrorCode_ParameterOutOfRange, - ErrorCode_BadParameterType, - ErrorCode_SQLiteNotOpened, - ErrorCode_SQLiteAlreadyOpened, - ErrorCode_SQLiteCannotOpen, - ErrorCode_SQLiteStatementAlreadyUsed, - ErrorCode_SQLiteExecute, - ErrorCode_SQLiteRollbackWithoutTransaction, - ErrorCode_SQLiteCommitWithoutTransaction, - ErrorCode_SQLiteRegisterFunction, - ErrorCode_SQLiteFlush, - ErrorCode_SQLiteCannotRun, - ErrorCode_SQLiteCannotStep, - ErrorCode_SQLiteBindOutOfRange, - ErrorCode_SQLitePrepareStatement, - ErrorCode_SQLiteTransactionAlreadyStarted, - ErrorCode_SQLiteTransactionCommit, - ErrorCode_SQLiteTransactionBegin - }; - - class OrthancSQLiteException : public ::std::runtime_error - { - public: - OrthancSQLiteException(ErrorCode error) : - ::std::runtime_error(EnumerationToString(error)) - { - } - - // Auto-generated by "Resources/GenerateErrorCodes.py" - static const char* EnumerationToString(ErrorCode code) - { - switch (code) - { - case ErrorCode_ParameterOutOfRange: - return "Parameter out of range"; - - case ErrorCode_BadParameterType: - return "Bad type for a parameter"; - - case ErrorCode_SQLiteNotOpened: - return "SQLite: The database is not opened"; - - case ErrorCode_SQLiteAlreadyOpened: - return "SQLite: Connection is already open"; - - case ErrorCode_SQLiteCannotOpen: - return "SQLite: Unable to open the database"; - - case ErrorCode_SQLiteStatementAlreadyUsed: - return "SQLite: This cached statement is already being referred to"; - - case ErrorCode_SQLiteExecute: - return "SQLite: Cannot execute a command"; - - case ErrorCode_SQLiteRollbackWithoutTransaction: - return "SQLite: Rolling back a nonexistent transaction (have you called Begin()?)"; - - case ErrorCode_SQLiteCommitWithoutTransaction: - return "SQLite: Committing a nonexistent transaction"; - - case ErrorCode_SQLiteRegisterFunction: - return "SQLite: Unable to register a function"; - - case ErrorCode_SQLiteFlush: - return "SQLite: Unable to flush the database"; - - case ErrorCode_SQLiteCannotRun: - return "SQLite: Cannot run a cached statement"; - - case ErrorCode_SQLiteCannotStep: - return "SQLite: Cannot step over a cached statement"; - - case ErrorCode_SQLiteBindOutOfRange: - return "SQLite: Bing a value while out of range (serious error)"; - - case ErrorCode_SQLitePrepareStatement: - return "SQLite: Cannot prepare a cached statement"; - - case ErrorCode_SQLiteTransactionAlreadyStarted: - return "SQLite: Beginning the same transaction twice"; - - case ErrorCode_SQLiteTransactionCommit: - return "SQLite: Failure when committing the transaction"; - - case ErrorCode_SQLiteTransactionBegin: - return "SQLite: Cannot start a transaction"; - - default: - return "Unknown error code"; - } - } - }; - } -} - -#else -# include "../OrthancException.h" -# define OrthancSQLiteException ::Orthanc::OrthancException -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/README.txt orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/README.txt --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/README.txt 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/README.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -Introduction -============ - -The code in this folder is a standalone object-oriented wrapper around -SQLite3. It is derived from the code of Chromium: - -http://src.chromium.org/viewvc/chrome/trunk/src/sql/ -http://maxradi.us/documents/sqlite/ - - -Main differences with Chromium -============================== - -* The reference counting mechanism has been reimplemented to make it - simpler. -* The OrthancException class is used for the exception mechanisms. -* A statement is always valid (is_valid() always return true). -* The classes and the methods have been renamed to meet Orthanc's - coding conventions. - - -Reuse in another software -========================= - -To use the Orthanc SQLite wrapper in another project than Orthanc, you -just have to define the "ORTHANC_SQLITE_STANDALONE" macro. - -All the C++ exceptions generated by the wrapper will be objects of the -class "::Orthanc::SQLite::OrthancSQLiteException", that derives from -the standard exception class "::std::runtime_error". - - -Licensing -========= - -The code in this folder is licensed under the 3-clause BSD license, in -order to respect the original license of the code. - -It is pretty straightforward to extract the code from this folder and -to include it in another project. diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/SQLiteTypes.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/SQLiteTypes.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/SQLiteTypes.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/SQLiteTypes.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of the CHU of Liege, nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -struct sqlite3; -struct sqlite3_context; -struct sqlite3_stmt; - -#if !defined(ORTHANC_SQLITE_VERSION) -#error Please define macro ORTHANC_SQLITE_VERSION -#endif - - -/** - * "sqlite3_value" is defined as: - * - "typedef struct Mem sqlite3_value;" up to SQLite <= 3.18.2 - * - "typedef struct sqlite3_value sqlite3_value;" since SQLite >= 3.19.0. - * We create our own copy of this typedef to get around this API incompatibility. - * https://github.com/mackyle/sqlite/commit/db1d90df06a78264775a14d22c3361eb5b42be17 - **/ - -#if ORTHANC_SQLITE_VERSION < 3019000 -struct Mem; -#else -struct sqlite3_value; -#endif - -namespace Orthanc -{ - namespace SQLite - { - namespace Internals - { -#if ORTHANC_SQLITE_VERSION < 3019000 - typedef struct ::Mem SQLiteValue; -#else - typedef struct ::sqlite3_value SQLiteValue; -#endif - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,370 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "Statement.h" -#include "Connection.h" - -#include -#include -#include - -#if (ORTHANC_SQLITE_STANDALONE == 1) -// Trace logging is disabled if this SQLite wrapper is used -// independently of Orthanc -# define LOG_CREATE(message); -# define LOG_APPLY(message); -#elif defined(NDEBUG) -// Trace logging is disabled in release builds -# include "../Logging.h" -# define LOG_CREATE(message); -# define LOG_APPLY(message); -#else -// Trace logging is enabled in debug builds -# include "../Logging.h" -# define LOG_CREATE(message) VLOG(1) << "SQLite::Statement create: " << message; -# define LOG_APPLY(message); // VLOG(1) << "SQLite::Statement apply: " << message; -#endif - -#include "sqlite3.h" - -#if defined(_MSC_VER) -#define snprintf _snprintf -#endif - - -namespace Orthanc -{ - namespace SQLite - { - int Statement::CheckError(int err, ErrorCode code) const - { - bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE); - if (!succeeded) - { -#if ORTHANC_SQLITE_STANDALONE != 1 - char buffer[128]; - snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err); - LOG(ERROR) << buffer; -#endif - - throw OrthancSQLiteException(code); - } - - return err; - } - - void Statement::CheckOk(int err, ErrorCode code) const - { - if (err == SQLITE_RANGE) - { - // Binding to a non-existent variable is evidence of a serious error. - throw OrthancSQLiteException(ErrorCode_SQLiteBindOutOfRange); - } - else if (err != SQLITE_OK) - { -#if ORTHANC_SQLITE_STANDALONE != 1 - char buffer[128]; - snprintf(buffer, sizeof(buffer) - 1, "SQLite error code %d", err); - LOG(ERROR) << buffer; -#endif - - throw OrthancSQLiteException(code); - } - } - - - Statement::Statement(Connection& database, - const StatementId& id, - const std::string& sql) : - reference_(database.GetCachedStatement(id, sql.c_str())) - { - Reset(true); - LOG_CREATE(sql); - } - - - Statement::Statement(Connection& database, - const StatementId& id, - const char* sql) : - reference_(database.GetCachedStatement(id, sql)) - { - Reset(true); - LOG_CREATE(sql); - } - - - Statement::Statement(Connection& database, - const std::string& sql) : - reference_(database.GetWrappedObject(), sql.c_str()) - { - LOG_CREATE(sql); - } - - - Statement::Statement(Connection& database, - const char* sql) : - reference_(database.GetWrappedObject(), sql) - { - LOG_CREATE(sql); - } - - - bool Statement::Run() - { - LOG_APPLY(sqlite3_sql(GetStatement())); - - return CheckError(sqlite3_step(GetStatement()), ErrorCode_SQLiteCannotRun) == SQLITE_DONE; - } - - bool Statement::Step() - { - LOG_APPLY(sqlite3_sql(GetStatement())); - - return CheckError(sqlite3_step(GetStatement()), ErrorCode_SQLiteCannotStep) == SQLITE_ROW; - } - - void Statement::Reset(bool clear_bound_vars) - { - // We don't call CheckError() here because sqlite3_reset() returns - // the last error that Step() caused thereby generating a second - // spurious error callback. - if (clear_bound_vars) - sqlite3_clear_bindings(GetStatement()); - //VLOG(1) << "SQLite::Statement::Reset"; - sqlite3_reset(GetStatement()); - } - - std::string Statement::GetOriginalSQLStatement() - { - return std::string(sqlite3_sql(GetStatement())); - } - - - void Statement::BindNull(int col) - { - CheckOk(sqlite3_bind_null(GetStatement(), col + 1), - ErrorCode_BadParameterType); - } - - void Statement::BindBool(int col, bool val) - { - BindInt(col, val ? 1 : 0); - } - - void Statement::BindInt(int col, int val) - { - CheckOk(sqlite3_bind_int(GetStatement(), col + 1, val), - ErrorCode_BadParameterType); - } - - void Statement::BindInt64(int col, int64_t val) - { - CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val), - ErrorCode_BadParameterType); - } - - void Statement::BindDouble(int col, double val) - { - CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val), - ErrorCode_BadParameterType); - } - - void Statement::BindCString(int col, const char* val) - { - CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT), - ErrorCode_BadParameterType); - } - - void Statement::BindString(int col, const std::string& val) - { - CheckOk(sqlite3_bind_text(GetStatement(), - col + 1, - val.data(), - static_cast(val.size()), - SQLITE_TRANSIENT), - ErrorCode_BadParameterType); - } - - /*void Statement::BindString16(int col, const string16& value) - { - BindString(col, UTF16ToUTF8(value)); - }*/ - - void Statement::BindBlob(int col, const void* val, int val_len) - { - CheckOk(sqlite3_bind_blob(GetStatement(), col + 1, val, val_len, SQLITE_TRANSIENT), - ErrorCode_BadParameterType); - } - - - int Statement::ColumnCount() const - { - return sqlite3_column_count(GetStatement()); - } - - - ColumnType Statement::GetColumnType(int col) const - { - // Verify that our enum matches sqlite's values. - assert(COLUMN_TYPE_INTEGER == SQLITE_INTEGER); - assert(COLUMN_TYPE_FLOAT == SQLITE_FLOAT); - assert(COLUMN_TYPE_TEXT == SQLITE_TEXT); - assert(COLUMN_TYPE_BLOB == SQLITE_BLOB); - assert(COLUMN_TYPE_NULL == SQLITE_NULL); - - return static_cast(sqlite3_column_type(GetStatement(), col)); - } - - ColumnType Statement::GetDeclaredColumnType(int col) const - { - std::string column_type(sqlite3_column_decltype(GetStatement(), col)); - std::transform(column_type.begin(), column_type.end(), column_type.begin(), tolower); - - if (column_type == "integer") - return COLUMN_TYPE_INTEGER; - else if (column_type == "float") - return COLUMN_TYPE_FLOAT; - else if (column_type == "text") - return COLUMN_TYPE_TEXT; - else if (column_type == "blob") - return COLUMN_TYPE_BLOB; - - return COLUMN_TYPE_NULL; - } - - bool Statement::ColumnIsNull(int col) const - { - return sqlite3_column_type(GetStatement(), col) == SQLITE_NULL; - } - - bool Statement::ColumnBool(int col) const - { - return !!ColumnInt(col); - } - - int Statement::ColumnInt(int col) const - { - return sqlite3_column_int(GetStatement(), col); - } - - int64_t Statement::ColumnInt64(int col) const - { - return sqlite3_column_int64(GetStatement(), col); - } - - double Statement::ColumnDouble(int col) const - { - return sqlite3_column_double(GetStatement(), col); - } - - std::string Statement::ColumnString(int col) const - { - const char* str = reinterpret_cast( - sqlite3_column_text(GetStatement(), col)); - int len = sqlite3_column_bytes(GetStatement(), col); - - std::string result; - if (str && len > 0) - result.assign(str, len); - return result; - } - - /*string16 Statement::ColumnString16(int col) const - { - std::string s = ColumnString(col); - return !s.empty() ? UTF8ToUTF16(s) : string16(); - }*/ - - int Statement::ColumnByteLength(int col) const - { - return sqlite3_column_bytes(GetStatement(), col); - } - - const void* Statement::ColumnBlob(int col) const - { - return sqlite3_column_blob(GetStatement(), col); - } - - bool Statement::ColumnBlobAsString(int col, std::string* blob) - { - const void* p = ColumnBlob(col); - size_t len = ColumnByteLength(col); - blob->resize(len); - if (blob->size() != len) { - return false; - } - blob->assign(reinterpret_cast(p), len); - return true; - } - - /*bool Statement::ColumnBlobAsString16(int col, string16* val) const - { - const void* data = ColumnBlob(col); - size_t len = ColumnByteLength(col) / sizeof(char16); - val->resize(len); - if (val->size() != len) - return false; - val->assign(reinterpret_cast(data), len); - return true; - }*/ - - /*bool Statement::ColumnBlobAsVector(int col, std::vector* val) const - { - val->clear(); - - const void* data = sqlite3_column_blob(GetStatement(), col); - int len = sqlite3_column_bytes(GetStatement(), col); - if (data && len > 0) { - val->resize(len); - memcpy(&(*val)[0], data, len); - } - return true; - }*/ - - /*bool Statement::ColumnBlobAsVector( - int col, - std::vector* val) const - { - return ColumnBlobAsVector(col, reinterpret_cast< std::vector* >(val)); - }*/ - - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Statement.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,174 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "NonCopyable.h" -#include "OrthancSQLiteException.h" -#include "StatementId.h" -#include "StatementReference.h" - -#include -#include - -#if ORTHANC_BUILD_UNIT_TESTS == 1 -# include -#endif - - -namespace Orthanc -{ - namespace SQLite - { - class Connection; - - // Possible return values from ColumnType in a statement. These - // should match the values in sqlite3.h. - enum ColumnType - { - COLUMN_TYPE_INTEGER = 1, - COLUMN_TYPE_FLOAT = 2, - COLUMN_TYPE_TEXT = 3, - COLUMN_TYPE_BLOB = 4, - COLUMN_TYPE_NULL = 5 - }; - - class Statement : public NonCopyable - { - friend class Connection; - -#if ORTHANC_BUILD_UNIT_TESTS == 1 - FRIEND_TEST(SQLStatementTest, Run); - FRIEND_TEST(SQLStatementTest, Reset); -#endif - - private: - StatementReference reference_; - - int CheckError(int err, - ErrorCode code) const; - - void CheckOk(int err, - ErrorCode code) const; - - struct sqlite3_stmt* GetStatement() const - { - return reference_.GetWrappedObject(); - } - - public: - Statement(Connection& database, - const std::string& sql); - - Statement(Connection& database, - const StatementId& id, - const std::string& sql); - - Statement(Connection& database, - const char* sql); - - Statement(Connection& database, - const StatementId& id, - const char* sql); - - ~Statement() - { - Reset(); - } - - bool Run(); - - bool Step(); - - // Diagnostics -------------------------------------------------------------- - - std::string GetOriginalSQLStatement(); - - - // Binding ------------------------------------------------------------------- - - // These all take a 0-based argument index - void BindNull(int col); - void BindBool(int col, bool val); - void BindInt(int col, int val); - void BindInt64(int col, int64_t val); - void BindDouble(int col, double val); - void BindCString(int col, const char* val); - void BindString(int col, const std::string& val); - //void BindString16(int col, const string16& value); - void BindBlob(int col, const void* value, int value_len); - - - // Retrieving ---------------------------------------------------------------- - - // Returns the number of output columns in the result. - int ColumnCount() const; - - // Returns the type associated with the given column. - // - // Watch out: the type may be undefined if you've done something to cause a - // "type conversion." This means requesting the value of a column of a type - // where that type is not the native type. For safety, call ColumnType only - // on a column before getting the value out in any way. - ColumnType GetColumnType(int col) const; - ColumnType GetDeclaredColumnType(int col) const; - - // These all take a 0-based argument index. - bool ColumnIsNull(int col) const ; - bool ColumnBool(int col) const; - int ColumnInt(int col) const; - int64_t ColumnInt64(int col) const; - double ColumnDouble(int col) const; - std::string ColumnString(int col) const; - //string16 ColumnString16(int col) const; - - // When reading a blob, you can get a raw pointer to the underlying data, - // along with the length, or you can just ask us to copy the blob into a - // vector. Danger! ColumnBlob may return NULL if there is no data! - int ColumnByteLength(int col) const; - const void* ColumnBlob(int col) const; - bool ColumnBlobAsString(int col, std::string* blob); - //bool ColumnBlobAsString16(int col, string16* val) const; - //bool ColumnBlobAsVector(int col, std::vector* val) const; - //bool ColumnBlobAsVector(int col, std::vector* val) const; - - // Resets the statement to its initial condition. This includes any current - // result row, and also the bound variables if the |clear_bound_vars| is true. - void Reset(bool clear_bound_vars = true); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "StatementId.h" - -#include - -namespace Orthanc -{ - namespace SQLite - { - bool StatementId::operator< (const StatementId& other) const - { - if (line_ != other.line_) - return line_ < other.line_; - - return strcmp(file_, other.file_) < 0; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementId.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -namespace Orthanc -{ - namespace SQLite - { - class StatementId - { - private: - const char* file_; - int line_; - - StatementId(); // Forbidden - - public: - StatementId(const char* file, int line) : file_(file), line_(line) - { - } - - bool operator< (const StatementId& other) const; - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "StatementReference.h" -#include "OrthancSQLiteException.h" - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../Logging.h" -#endif - -#include -#include -#include "sqlite3.h" - -namespace Orthanc -{ - namespace SQLite - { - bool StatementReference::IsRoot() const - { - return root_ == NULL; - } - - StatementReference::StatementReference() - { - root_ = NULL; - refCount_ = 0; - statement_ = NULL; - assert(IsRoot()); - } - - StatementReference::StatementReference(sqlite3* database, - const char* sql) - { - if (database == NULL || sql == NULL) - { - throw OrthancSQLiteException(ErrorCode_ParameterOutOfRange); - } - - root_ = NULL; - refCount_ = 0; - - int error = sqlite3_prepare_v2(database, sql, -1, &statement_, NULL); - if (error != SQLITE_OK) - { -#if ORTHANC_SQLITE_STANDALONE != 1 - int extended = sqlite3_extended_errcode(database); - LOG(ERROR) << "SQLite: " << sqlite3_errmsg(database) << " (" << extended << ")"; - if (extended == SQLITE_IOERR_SHMSIZE /* 4874 */) - { - LOG(ERROR) << " This probably indicates that your filesystem is full"; - } -#endif - - throw OrthancSQLiteException(ErrorCode_SQLitePrepareStatement); - } - - assert(IsRoot()); - } - - StatementReference::StatementReference(StatementReference& other) - { - refCount_ = 0; - - if (other.IsRoot()) - { - root_ = &other; - } - else - { - root_ = other.root_; - } - - root_->refCount_++; - statement_ = root_->statement_; - - assert(!IsRoot()); - } - - StatementReference::~StatementReference() - { - if (IsRoot()) - { - if (refCount_ != 0) - { - // There remain references to this object. We cannot throw - // an exception because: - // http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html - -#if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "Bad value of the reference counter"; -#endif - } - else if (statement_ != NULL) - { - sqlite3_finalize(statement_); - } - } - else - { - if (root_->refCount_ == 0) - { - // There remain references to this object. We cannot throw - // an exception because: - // http://www.parashift.com/c++-faq/dtors-shouldnt-throw.html - -#if ORTHANC_SQLITE_STANDALONE != 1 - LOG(ERROR) << "Bad value of the reference counter"; -#endif - } - else - { - root_->refCount_--; - } - } - } - - uint32_t StatementReference::GetReferenceCount() const - { - return refCount_; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/StatementReference.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "NonCopyable.h" -#include "SQLiteTypes.h" - -#include -#include -#include - - -namespace Orthanc -{ - namespace SQLite - { - class StatementReference : NonCopyable - { - private: - StatementReference* root_; // Only used for non-root nodes - uint32_t refCount_; // Only used for root node - struct sqlite3_stmt* statement_; - - bool IsRoot() const; - - public: - StatementReference(); - - StatementReference(sqlite3* database, - const char* sql); - - StatementReference(StatementReference& other); - - ~StatementReference(); - - uint32_t GetReferenceCount() const; - - struct sqlite3_stmt* GetWrappedObject() const - { - assert(statement_ != NULL); - return statement_; - } - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,104 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#if ORTHANC_SQLITE_STANDALONE != 1 -#include "../PrecompiledHeaders.h" -#endif - -#include "Transaction.h" -#include "OrthancSQLiteException.h" - -namespace Orthanc -{ - namespace SQLite - { - Transaction::Transaction(Connection& connection) : - connection_(connection), - isOpen_(false) - { - } - - Transaction::~Transaction() - { - if (isOpen_) - { - connection_.RollbackTransaction(); - } - } - - void Transaction::Begin() - { - if (isOpen_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteTransactionAlreadyStarted); - } - - isOpen_ = connection_.BeginTransaction(); - if (!isOpen_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteTransactionBegin); - } - } - - void Transaction::Rollback() - { - if (!isOpen_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction); - } - - isOpen_ = false; - - connection_.RollbackTransaction(); - } - - void Transaction::Commit() - { - if (!isOpen_) - { - throw OrthancSQLiteException(ErrorCode_SQLiteRollbackWithoutTransaction); - } - - isOpen_ = false; - - if (!connection_.CommitTransaction()) - { - throw OrthancSQLiteException(ErrorCode_SQLiteTransactionCommit); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SQLite/Transaction.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * - * Copyright (C) 2012-2016 Sebastien Jodogne , - * Medical Physics Department, CHU of Liege, Belgium - * - * Copyright (c) 2012 The Chromium Authors. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc., the name of the CHU of Liege, - * nor the names of its contributors may be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * OWNER OR CONTRIBUTORS 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. - **/ - - -#pragma once - -#include "Connection.h" -#include "ITransaction.h" - -namespace Orthanc -{ - namespace SQLite - { - class Transaction : public ITransaction - { - private: - Connection& connection_; - - // True when the transaction is open, false when it's already been committed - // or rolled back. - bool isOpen_; - - public: - explicit Transaction(Connection& connection); - - virtual ~Transaction(); - - // Returns true when there is a transaction that has been successfully begun. - bool IsOpen() const { return isOpen_; } - - virtual void Begin(); - - virtual void Rollback(); - - virtual void Commit(); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,764 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "SystemToolbox.h" - - -#if defined(_WIN32) -# include -# include // For "_spawnvp()" and "_getpid()" -# include // For "environ" -#else -# include // For "execvp()" -# include // For "waitpid()" -#endif - - -#if defined(__APPLE__) && defined(__MACH__) -# include /* _NSGetExecutablePath */ -# include /* PATH_MAX */ -#endif - - -#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) -# include /* PATH_MAX */ -# include -# include -#endif - - -#if defined(__OpenBSD__) -# include // For "sysctl", "CTL_KERN" and "KERN_PROC_ARGS" -#endif - - -#include "Logging.h" -#include "OrthancException.h" -#include "Toolbox.h" - -#include -#include -#include -#include - - -/*========================================================================= - The section below comes from the Boost 1.68.0 project: - https://github.com/boostorg/program_options/blob/boost-1.68.0/src/parsers.cpp - - Copyright Vladimir Prus 2002-2004. - Distributed under the Boost Software License, Version 1.0. - (See accompanying file LICENSE_1_0.txt - or copy at http://www.boost.org/LICENSE_1_0.txt) - =========================================================================*/ - -// The 'environ' should be declared in some cases. E.g. Linux man page says: -// (This variable must be declared in the user program, but is declared in -// the header file unistd.h in case the header files came from libc4 or libc5, -// and in case they came from glibc and _GNU_SOURCE was defined.) -// To be safe, declare it here. - -// It appears that on Mac OS X the 'environ' variable is not -// available to dynamically linked libraries. -// See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843 -// See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html -#if defined(__APPLE__) && defined(__DYNAMIC__) -// The proper include for this is crt_externs.h, however it's not -// available on iOS. The right replacement is not known. See -// https://svn.boost.org/trac/boost/ticket/5053 -extern "C" -{ - extern char ***_NSGetEnviron(void); -} -# define environ (*_NSGetEnviron()) -#else -# if defined(__MWERKS__) -# include -# else -# if !defined(_WIN32) || defined(__COMO_VERSION__) -extern char** environ; -# endif -# endif -#endif - - -/*========================================================================= - End of section from the Boost 1.68.0 project - =========================================================================*/ - - -namespace Orthanc -{ - static bool finish_; - static ServerBarrierEvent barrierEvent_; - -#if defined(_WIN32) - static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType) - { - // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx - finish_ = true; - return true; - } -#else - static void SignalHandler(int signal) - { - if (signal == SIGHUP) - { - barrierEvent_ = ServerBarrierEvent_Reload; - } - - finish_ = true; - } -#endif - - - static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag) - { -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, true); -#else - signal(SIGINT, SignalHandler); - signal(SIGQUIT, SignalHandler); - signal(SIGTERM, SignalHandler); - signal(SIGHUP, SignalHandler); -#endif - - // Active loop that awakens every 100ms - finish_ = false; - barrierEvent_ = ServerBarrierEvent_Stop; - while (!(*stopFlag || finish_)) - { - SystemToolbox::USleep(100 * 1000); - } - -#if defined(_WIN32) - SetConsoleCtrlHandler(ConsoleControlHandler, false); -#else - signal(SIGINT, NULL); - signal(SIGQUIT, NULL); - signal(SIGTERM, NULL); - signal(SIGHUP, NULL); -#endif - - return barrierEvent_; - } - - - ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag) - { - return ServerBarrierInternal(&stopFlag); - } - - - ServerBarrierEvent SystemToolbox::ServerBarrier() - { - const bool stopFlag = false; - return ServerBarrierInternal(&stopFlag); - } - - - void SystemToolbox::USleep(uint64_t microSeconds) - { -#if defined(_WIN32) - ::Sleep(static_cast(microSeconds / static_cast(1000))); -#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__native_client__) - usleep(microSeconds); -#else -#error Support your platform here -#endif - } - - - static std::streamsize GetStreamSize(std::istream& f) - { - // http://www.cplusplus.com/reference/iostream/istream/tellg/ - f.seekg(0, std::ios::end); - std::streamsize size = f.tellg(); - f.seekg(0, std::ios::beg); - - return size; - } - - - void SystemToolbox::ReadFile(std::string& content, - const std::string& path, - bool log) - { - if (!IsRegularFile(path)) - { - throw OrthancException(ErrorCode_RegularFileExpected, - "The path does not point to a regular file: " + path, - log); - } - - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile, - "File not found: " + path, - log); - } - - std::streamsize size = GetStreamSize(f); - content.resize(static_cast(size)); - if (size != 0) - { - f.read(&content[0], size); - } - - f.close(); - } - - - bool SystemToolbox::ReadHeader(std::string& header, - const std::string& path, - size_t headerSize) - { - if (!IsRegularFile(path)) - { - throw OrthancException(ErrorCode_RegularFileExpected, - "The path does not point to a regular file: " + path); - } - - boost::filesystem::ifstream f; - f.open(path, std::ifstream::in | std::ifstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_InexistentFile); - } - - bool full = true; - - { - std::streamsize size = GetStreamSize(f); - if (size <= 0) - { - headerSize = 0; - full = false; - } - else if (static_cast(size) < headerSize) - { - headerSize = static_cast(size); // Truncate to the size of the file - full = false; - } - } - - header.resize(headerSize); - if (headerSize != 0) - { - f.read(&header[0], headerSize); - } - - f.close(); - - return full; - } - - - void SystemToolbox::WriteFile(const void* content, - size_t size, - const std::string& path) - { - boost::filesystem::ofstream f; - f.open(path, std::ofstream::out | std::ofstream::binary); - if (!f.good()) - { - throw OrthancException(ErrorCode_CannotWriteFile); - } - - if (size != 0) - { - f.write(reinterpret_cast(content), size); - - if (!f.good()) - { - f.close(); - throw OrthancException(ErrorCode_FileStorageCannotWrite); - } - } - - f.close(); - } - - - void SystemToolbox::WriteFile(const std::string& content, - const std::string& path) - { - WriteFile(content.size() > 0 ? content.c_str() : NULL, - content.size(), path); - } - - - void SystemToolbox::RemoveFile(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (IsRegularFile(path)) - { - boost::filesystem::remove(path); - } - else - { - throw OrthancException(ErrorCode_RegularFileExpected); - } - } - } - - - uint64_t SystemToolbox::GetFileSize(const std::string& path) - { - try - { - return static_cast(boost::filesystem::file_size(path)); - } - catch (boost::filesystem::filesystem_error&) - { - throw OrthancException(ErrorCode_InexistentFile); - } - } - - - void SystemToolbox::MakeDirectory(const std::string& path) - { - if (boost::filesystem::exists(path)) - { - if (!boost::filesystem::is_directory(path)) - { - throw OrthancException(ErrorCode_DirectoryOverFile); - } - } - else - { - if (!boost::filesystem::create_directories(path)) - { - throw OrthancException(ErrorCode_MakeDirectory); - } - } - } - - - bool SystemToolbox::IsExistingFile(const std::string& path) - { - return boost::filesystem::exists(path); - } - - -#if defined(_WIN32) - static std::string GetPathToExecutableInternal() - { - // Yes, this is ugly, but there is no simple way to get the - // required buffer size, so we use a big constant - std::vector buffer(32768); - /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast(buffer.size() - 1)); - return std::string(&buffer[0]); - } - -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) - static std::string GetPathToExecutableInternal() - { - // NOTE: For FreeBSD, using KERN_PROC_PATHNAME might be a better alternative - - std::vector buffer(PATH_MAX + 1); - ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); - if (bytes == 0) - { - throw OrthancException(ErrorCode_PathToExecutable); - } - - return std::string(&buffer[0]); - } - -#elif defined(__APPLE__) && defined(__MACH__) - static std::string GetPathToExecutableInternal() - { - char pathbuf[PATH_MAX + 1]; - unsigned int bufsize = static_cast(sizeof(pathbuf)); - - _NSGetExecutablePath( pathbuf, &bufsize); - - return std::string(pathbuf); - } - -#elif defined(__OpenBSD__) - static std::string GetPathToExecutableInternal() - { - // This is an adapted version of the patch proposed in issue #64 - // without an explicit call to "malloc()" to prevent memory leak - // https://bitbucket.org/sjodogne/orthanc/issues/64/add-openbsd-support - // https://stackoverflow.com/q/31494901/881731 - - const int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; - - size_t len; - if (sysctl(mib, 4, NULL, &len, NULL, 0) == -1) - { - throw OrthancException(ErrorCode_PathToExecutable); - } - - std::string tmp; - tmp.resize(len); - - char** buffer = reinterpret_cast(&tmp[0]); - - if (sysctl(mib, 4, buffer, &len, NULL, 0) == -1) - { - throw OrthancException(ErrorCode_PathToExecutable); - } - else - { - return std::string(buffer[0]); - } - } - -#else -#error Support your platform here -#endif - - - std::string SystemToolbox::GetPathToExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p).string(); - } - - - std::string SystemToolbox::GetDirectoryOfExecutable() - { - boost::filesystem::path p(GetPathToExecutableInternal()); - return boost::filesystem::absolute(p.parent_path()).string(); - } - - - void SystemToolbox::ExecuteSystemCommand(const std::string& command, - const std::vector& arguments) - { - // Convert the arguments as a C array - std::vector args(arguments.size() + 2); - - args.front() = const_cast(command.c_str()); - - for (size_t i = 0; i < arguments.size(); i++) - { - args[i + 1] = const_cast(arguments[i].c_str()); - } - - args.back() = NULL; - - int status; - -#if defined(_WIN32) - // http://msdn.microsoft.com/en-us/library/275khfab.aspx - status = static_cast(_spawnvp(_P_OVERLAY, command.c_str(), &args[0])); - -#else - int pid = fork(); - - if (pid == -1) - { - // Error in fork() - throw OrthancException(ErrorCode_SystemCommand, "Cannot fork a child process"); - } - else if (pid == 0) - { - // Execute the system command in the child process - execvp(command.c_str(), &args[0]); - - // We should never get here - _exit(1); - } - else - { - // Wait for the system command to exit - waitpid(pid, &status, 0); - } -#endif - - if (status != 0) - { - throw OrthancException(ErrorCode_SystemCommand, - "System command failed with status code " + - boost::lexical_cast(status)); - } - } - - - int SystemToolbox::GetProcessId() - { -#if defined(_WIN32) - return static_cast(_getpid()); -#else - return static_cast(getpid()); -#endif - } - - - bool SystemToolbox::IsRegularFile(const std::string& path) - { - namespace fs = boost::filesystem; - - try - { - if (fs::exists(path)) - { - fs::file_status status = fs::status(path); - return (status.type() == boost::filesystem::regular_file || - status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11 - } - } - catch (fs::filesystem_error&) - { - } - - return false; - } - - - FILE* SystemToolbox::OpenFile(const std::string& path, - FileMode mode) - { -#if defined(_WIN32) - // TODO Deal with special characters by converting to the current locale -#endif - - const char* m; - switch (mode) - { - case FileMode_ReadBinary: - m = "rb"; - break; - - case FileMode_WriteBinary: - m = "wb"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - return fopen(path.c_str(), m); - } - - - static boost::posix_time::ptime GetNow(bool utc) - { - if (utc) - { - return boost::posix_time::second_clock::universal_time(); - } - else - { - return boost::posix_time::second_clock::local_time(); - } - } - - - std::string SystemToolbox::GetNowIsoString(bool utc) - { - return boost::posix_time::to_iso_string(GetNow(utc)); - } - - - void SystemToolbox::GetNowDicom(std::string& date, - std::string& time, - bool utc) - { - boost::posix_time::ptime now = GetNow(utc); - tm tm = boost::posix_time::to_tm(now); - - char s[32]; - sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - date.assign(s); - - // TODO milliseconds - sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0); - time.assign(s); - } - - - unsigned int SystemToolbox::GetHardwareConcurrency() - { - // Get the number of available hardware threads (e.g. number of - // CPUs or cores or hyperthreading units) - unsigned int threads = boost::thread::hardware_concurrency(); - - if (threads <= 0) - { - return 1; - } - else - { - return threads; - } - } - - - MimeType SystemToolbox::AutodetectMimeType(const std::string& path) - { - std::string extension = boost::filesystem::extension(path); - Toolbox::ToLowerCase(extension); - - // http://en.wikipedia.org/wiki/Mime_types - // Text types - if (extension == ".txt") - { - return MimeType_PlainText; - } - else if (extension == ".html") - { - return MimeType_Html; - } - else if (extension == ".xml") - { - return MimeType_Xml; - } - else if (extension == ".css") - { - return MimeType_Css; - } - - // Application types - else if (extension == ".js") - { - return MimeType_JavaScript; - } - else if (extension == ".json" || - extension == ".nmf" /* manifest */) - { - return MimeType_Json; - } - else if (extension == ".pdf") - { - return MimeType_Pdf; - } - else if (extension == ".wasm") - { - return MimeType_WebAssembly; - } - else if (extension == ".nexe") - { - return MimeType_NaCl; - } - else if (extension == ".pexe") - { - return MimeType_PNaCl; - } - - // Images types - else if (extension == ".jpg" || - extension == ".jpeg") - { - return MimeType_Jpeg; - } - else if (extension == ".gif") - { - return MimeType_Gif; - } - else if (extension == ".png") - { - return MimeType_Png; - } - else if (extension == ".pam") - { - return MimeType_Pam; - } - else if (extension == ".svg") - { - return MimeType_Svg; - } - - // Various types - else if (extension == ".woff") - { - return MimeType_Woff; - } - else if (extension == ".woff2") - { - return MimeType_Woff2; - } - - // Default type - else - { - LOG(INFO) << "Unknown MIME type for extension \"" << extension << "\""; - return MimeType_Binary; - } - } - - - void SystemToolbox::GetEnvironmentVariables(std::map& env) - { - env.clear(); - - for (char **p = environ; *p != NULL; p++) - { - std::string v(*p); - size_t pos = v.find('='); - - if (pos != std::string::npos) - { - std::string key = v.substr(0, pos); - std::string value = v.substr(pos + 1); - env[key] = value; - } - } - } - - - std::string SystemToolbox::InterpretRelativePath(const std::string& baseDirectory, - const std::string& relativePath) - { - boost::filesystem::path base(baseDirectory); - boost::filesystem::path relative(relativePath); - - /** - The following lines should be equivalent to this one: - - return (base / relative).string(); - - However, for some unknown reason, some versions of Boost do not - make the proper path resolution when "baseDirectory" is an - absolute path. So, a hack is used below. - **/ - - if (relative.is_absolute()) - { - return relative.string(); - } - else - { - return (base / relative).string(); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/SystemToolbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The namespace SystemToolbox cannot be used in sandboxed environments -#endif - -#include "Enumerations.h" - -#include -#include -#include -#include - -namespace Orthanc -{ - namespace SystemToolbox - { - void USleep(uint64_t microSeconds); - - ServerBarrierEvent ServerBarrier(const bool& stopFlag); - - ServerBarrierEvent ServerBarrier(); - - void ReadFile(std::string& content, - const std::string& path, - bool log = true); - - bool ReadHeader(std::string& header, - const std::string& path, - size_t headerSize); - - void WriteFile(const void* content, - size_t size, - const std::string& path); - - void WriteFile(const std::string& content, - const std::string& path); - - void RemoveFile(const std::string& path); - - uint64_t GetFileSize(const std::string& path); - - void MakeDirectory(const std::string& path); - - bool IsExistingFile(const std::string& path); - - std::string GetPathToExecutable(); - - std::string GetDirectoryOfExecutable(); - - void ExecuteSystemCommand(const std::string& command, - const std::vector& arguments); - - int GetProcessId(); - - bool IsRegularFile(const std::string& path); - - FILE* OpenFile(const std::string& path, - FileMode mode); - - std::string GetNowIsoString(bool utc); - - void GetNowDicom(std::string& date, - std::string& time, - bool utc); - - unsigned int GetHardwareConcurrency(); - - MimeType AutodetectMimeType(const std::string& path); - - void GetEnvironmentVariables(std::map& env); - - std::string InterpretRelativePath(const std::string& baseDirectory, - const std::string& relativePath); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "TemporaryFile.h" - -#include "OrthancException.h" -#include "SystemToolbox.h" -#include "Toolbox.h" - -#include - -namespace Orthanc -{ - static std::string CreateTemporaryPath(const char* temporaryDirectory, - const char* extension) - { - boost::filesystem::path dir; - - if (temporaryDirectory == NULL) - { -#if BOOST_HAS_FILESYSTEM_V3 == 1 - dir = boost::filesystem::temp_directory_path(); -#elif defined(__linux__) - dir = "/tmp"; -#else -# error Support your platform here -#endif - } - else - { - dir = temporaryDirectory; - } - - // We use UUID to create unique path to temporary files - const std::string uuid = Orthanc::Toolbox::GenerateUuid(); - - // New in Orthanc 1.5.8: Prefix the process ID to the name of the - // temporary files, in order to locate orphan temporary files that - // were left by instances of Orthanc that exited in non-clean way - // https://groups.google.com/d/msg/orthanc-users/MSJX53bw6Lw/d3S3lRRLAwAJ - std::string filename = "Orthanc-" + boost::lexical_cast(SystemToolbox::GetProcessId()) + "-" + uuid; - - if (extension != NULL) - { - filename.append(extension); - } - - dir /= filename; - return dir.string(); - } - - - TemporaryFile::TemporaryFile() : - path_(CreateTemporaryPath(NULL, NULL)) - { - } - - - TemporaryFile::TemporaryFile(const std::string& temporaryDirectory, - const std::string& extension) : - path_(CreateTemporaryPath(temporaryDirectory.c_str(), extension.c_str())) - { - } - - - TemporaryFile::~TemporaryFile() - { - boost::filesystem::remove(path_); - } - - - void TemporaryFile::Write(const std::string& content) - { - try - { - SystemToolbox::WriteFile(content, path_); - } - catch (OrthancException& e) - { - throw OrthancException(e.GetErrorCode(), - "Can't create temporary file \"" + path_ + - "\" with " + boost::lexical_cast(content.size()) + - " bytes: Check you have write access to the " - "temporary directory and that it is not full"); - } - } - - - void TemporaryFile::Read(std::string& content) const - { - try - { - SystemToolbox::ReadFile(content, path_); - } - catch (OrthancException& e) - { - throw OrthancException(e.GetErrorCode(), - "Can't read temporary file \"" + path_ + - "\": Another process has corrupted the temporary directory"); - } - } - - - void TemporaryFile::Touch() - { - std::string empty; - Write(empty); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/TemporaryFile.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#if ORTHANC_SANDBOXED == 1 -# error The class TemporaryFile cannot be used in sandboxed environments -#endif - -#include - -namespace Orthanc -{ - class TemporaryFile - { - private: - std::string path_; - - public: - TemporaryFile(); - - TemporaryFile(const std::string& temporaryFolder, - const std::string& extension); - - ~TemporaryFile(); - - const std::string& GetPath() const - { - return path_; - } - - void Write(const std::string& content); - - void Read(std::string& content) const; - - void Touch(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2257 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "Toolbox.h" - -#include "Compatibility.h" -#include "OrthancException.h" -#include "Logging.h" - -#include -#include -#include -#include - -#if BOOST_VERSION >= 106600 -# include -#else -# include -#endif - -#include -#include -#include -#include -#include - - -#if ORTHANC_ENABLE_MD5 == 1 -// TODO - Could be replaced by starting -// with Boost >= 1.66.0 -# include "../Resources/ThirdParty/md5/md5.h" -#endif - -#if ORTHANC_ENABLE_BASE64 == 1 -# include "../Resources/ThirdParty/base64/base64.h" -#endif - -#if ORTHANC_ENABLE_LOCALE == 1 -# include -#endif - -#if ORTHANC_ENABLE_SSL == 1 -// For OpenSSL initialization and finalization -# include -# include -# include -# include -# include -#endif - - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -// Patch for the missing "_strtoll" symbol when compiling with Visual Studio < 2013 -extern "C" -{ - int64_t _strtoi64(const char *nptr, char **endptr, int base); - int64_t strtoll(const char *nptr, char **endptr, int base) - { - return _strtoi64(nptr, endptr, base); - } -} -#endif - - -#if defined(_WIN32) -# include // For ::Sleep -#endif - - -#if ORTHANC_ENABLE_PUGIXML == 1 -# include "ChunkedBuffer.h" -#endif - - -// Inclusions for UUID -// http://stackoverflow.com/a/1626302 - -extern "C" -{ -#if defined(_WIN32) -# include -#else -# include -#endif -} - - -#if defined(ORTHANC_STATIC_ICU) -# if (ORTHANC_STATIC_ICU == 1 && ORTHANC_ENABLE_LOCALE == 1) -# include -# include -# include -# include "Compression/GzipCompressor.h" - -static std::string globalIcuData_; - -extern "C" -{ - // This is dummy content for the "icudt58_dat" (resp. "icudt63_dat") - // global variable from the autogenerated "icudt58l_dat.c" - // (resp. "icudt63l_dat.c") file that contains a huge C array. In - // Orthanc, this array is compressed using gzip and attached as a - // resource, then uncompressed during the launch of Orthanc by - // static function "InitializeIcu()". - struct - { - double bogus; - uint8_t *bytes; - } U_ICUDATA_ENTRY_POINT = { 0.0, NULL }; -} - -# if defined(__LSB_VERSION__) -extern "C" -{ - /** - * The "tzname" global variable is declared as "extern" but is not - * defined in any compilation module, if using Linux Standard Base, - * as soon as OpenSSL or cURL is in use on Ubuntu >= 18.04 (glibc >= - * 2.27). The variable "__tzname" is always properly declared *and* - * defined. The reason is unclear, and is maybe a bug in the gcc 4.8 - * linker that is used by LSB if facing a weak symbol (as "tzname"). - * This makes Orthanc crash if the timezone is set to UTC. - * https://groups.google.com/d/msg/orthanc-users/0m8sxxwSm1E/2p8du_89CAAJ - **/ - char *tzname[2] = { (char *) "GMT", (char *) "GMT" }; -} -# endif - -# endif -#endif - - - -#if defined(__unix__) && ORTHANC_SANDBOXED != 1 -# include "SystemToolbox.h" // Check out "InitializeGlobalLocale()" -#endif - - - -namespace Orthanc -{ - void Toolbox::LinesIterator::FindEndOfLine() - { - lineEnd_ = lineStart_; - - while (lineEnd_ < content_.size() && - content_[lineEnd_] != '\n' && - content_[lineEnd_] != '\r') - { - lineEnd_ += 1; - } - } - - - Toolbox::LinesIterator::LinesIterator(const std::string& content) : - content_(content), - lineStart_(0) - { - FindEndOfLine(); - } - - - bool Toolbox::LinesIterator::GetLine(std::string& target) const - { - assert(lineStart_ <= content_.size() && - lineEnd_ <= content_.size() && - lineStart_ <= lineEnd_); - - if (lineStart_ == content_.size()) - { - return false; - } - else - { - target = content_.substr(lineStart_, lineEnd_ - lineStart_); - return true; - } - } - - - void Toolbox::LinesIterator::Next() - { - lineStart_ = lineEnd_; - - if (lineStart_ != content_.size()) - { - assert(content_[lineStart_] == '\r' || - content_[lineStart_] == '\n'); - - char second; - - if (content_[lineStart_] == '\r') - { - second = '\n'; - } - else - { - second = '\r'; - } - - lineStart_ += 1; - - if (lineStart_ < content_.size() && - content_[lineStart_] == second) - { - lineStart_ += 1; - } - - FindEndOfLine(); - } - } - - - void Toolbox::ToUpperCase(std::string& s) - { - std::transform(s.begin(), s.end(), s.begin(), toupper); - } - - - void Toolbox::ToLowerCase(std::string& s) - { - std::transform(s.begin(), s.end(), s.begin(), tolower); - } - - - void Toolbox::ToUpperCase(std::string& result, - const std::string& source) - { - result = source; - ToUpperCase(result); - } - - void Toolbox::ToLowerCase(std::string& result, - const std::string& source) - { - result = source; - ToLowerCase(result); - } - - - void Toolbox::SplitUriComponents(UriComponents& components, - const std::string& uri) - { - static const char URI_SEPARATOR = '/'; - - components.clear(); - - if (uri.size() == 0 || - uri[0] != URI_SEPARATOR) - { - throw OrthancException(ErrorCode_UriSyntax); - } - - // Count the number of slashes in the URI to make an assumption - // about the number of components in the URI - unsigned int estimatedSize = 0; - for (unsigned int i = 0; i < uri.size(); i++) - { - if (uri[i] == URI_SEPARATOR) - estimatedSize++; - } - - components.reserve(estimatedSize - 1); - - unsigned int start = 1; - unsigned int end = 1; - while (end < uri.size()) - { - // This is the loop invariant - assert(uri[start - 1] == '/' && (end >= start)); - - if (uri[end] == '/') - { - components.push_back(std::string(&uri[start], end - start)); - end++; - start = end; - } - else - { - end++; - } - } - - if (start < uri.size()) - { - components.push_back(std::string(&uri[start], end - start)); - } - - for (size_t i = 0; i < components.size(); i++) - { - if (components[i].size() == 0) - { - // Empty component, as in: "/coucou//e" - throw OrthancException(ErrorCode_UriSyntax); - } - } - } - - - void Toolbox::TruncateUri(UriComponents& target, - const UriComponents& source, - size_t fromLevel) - { - target.clear(); - - if (source.size() > fromLevel) - { - target.resize(source.size() - fromLevel); - - size_t j = 0; - for (size_t i = fromLevel; i < source.size(); i++, j++) - { - target[j] = source[i]; - } - - assert(j == target.size()); - } - } - - - - bool Toolbox::IsChildUri(const UriComponents& baseUri, - const UriComponents& testedUri) - { - if (testedUri.size() < baseUri.size()) - { - return false; - } - - for (size_t i = 0; i < baseUri.size(); i++) - { - if (baseUri[i] != testedUri[i]) - return false; - } - - return true; - } - - - std::string Toolbox::FlattenUri(const UriComponents& components, - size_t fromLevel) - { - if (components.size() <= fromLevel) - { - return "/"; - } - else - { - std::string r; - - for (size_t i = fromLevel; i < components.size(); i++) - { - r += "/" + components[i]; - } - - return r; - } - } - - -#if ORTHANC_ENABLE_MD5 == 1 - static char GetHexadecimalCharacter(uint8_t value) - { - assert(value < 16); - - if (value < 10) - { - return value + '0'; - } - else - { - return (value - 10) + 'a'; - } - } - - - void Toolbox::ComputeMD5(std::string& result, - const std::string& data) - { - if (data.size() > 0) - { - ComputeMD5(result, &data[0], data.size()); - } - else - { - ComputeMD5(result, NULL, 0); - } - } - - - void Toolbox::ComputeMD5(std::string& result, - const void* data, - size_t size) - { - md5_state_s state; - md5_init(&state); - - if (size > 0) - { - md5_append(&state, - reinterpret_cast(data), - static_cast(size)); - } - - md5_byte_t actualHash[16]; - md5_finish(&state, actualHash); - - result.resize(32); - for (unsigned int i = 0; i < 16; i++) - { - result[2 * i] = GetHexadecimalCharacter(static_cast(actualHash[i] / 16)); - result[2 * i + 1] = GetHexadecimalCharacter(static_cast(actualHash[i] % 16)); - } - } -#endif - - -#if ORTHANC_ENABLE_BASE64 == 1 - void Toolbox::EncodeBase64(std::string& result, - const std::string& data) - { - result.clear(); - base64_encode(result, data); - } - - void Toolbox::DecodeBase64(std::string& result, - const std::string& data) - { - for (size_t i = 0; i < data.length(); i++) - { - if (!isalnum(data[i]) && - data[i] != '+' && - data[i] != '/' && - data[i] != '=') - { - // This is not a valid character for a Base64 string - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - result.clear(); - base64_decode(result, data); - } - - - bool Toolbox::DecodeDataUriScheme(std::string& mime, - std::string& content, - const std::string& source) - { - boost::regex pattern("data:([^;]+);base64,([a-zA-Z0-9=+/]*)", - boost::regex::icase /* case insensitive search */); - - boost::cmatch what; - if (regex_match(source.c_str(), what, pattern)) - { - mime = what[1]; - DecodeBase64(content, what[2]); - return true; - } - else - { - return false; - } - } - - - void Toolbox::EncodeDataUriScheme(std::string& result, - const std::string& mime, - const std::string& content) - { - result = "data:" + mime + ";base64,"; - base64_encode(result, content); - } - -#endif - - -#if ORTHANC_ENABLE_LOCALE == 1 - static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding) - { - switch (sourceEncoding) - { - case Encoding_Utf8: - return "UTF-8"; - - case Encoding_Ascii: - return "ASCII"; - - case Encoding_Latin1: - return "ISO-8859-1"; - - case Encoding_Latin2: - return "ISO-8859-2"; - - case Encoding_Latin3: - return "ISO-8859-3"; - - case Encoding_Latin4: - return "ISO-8859-4"; - - case Encoding_Latin5: - return "ISO-8859-9"; - - case Encoding_Cyrillic: - return "ISO-8859-5"; - - case Encoding_Windows1251: - return "WINDOWS-1251"; - - case Encoding_Arabic: - return "ISO-8859-6"; - - case Encoding_Greek: - return "ISO-8859-7"; - - case Encoding_Hebrew: - return "ISO-8859-8"; - - case Encoding_Japanese: - return "SHIFT-JIS"; - - case Encoding_Chinese: - return "GB18030"; - - case Encoding_Thai: -#if BOOST_LOCALE_WITH_ICU == 1 - return "tis620.2533"; -#else - return "TIS620.2533-0"; -#endif - - case Encoding_Korean: - return "ISO-IR-149"; - - case Encoding_JapaneseKanji: - return "JIS"; - - case Encoding_SimplifiedChinese: - return "GB2312"; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } -#endif - - -#if ORTHANC_ENABLE_LOCALE == 1 - // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.12.html#sect_C.12.1.1.2 - std::string Toolbox::ConvertToUtf8(const std::string& source, - Encoding sourceEncoding, - bool hasCodeExtensions) - { -#if ORTHANC_STATIC_ICU == 1 - if (globalIcuData_.empty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Call Toolbox::InitializeGlobalLocale()"); - } -#endif - - // The "::skip" flag makes boost skip invalid UTF-8 - // characters. This can occur in badly-encoded DICOM files. - - try - { - if (sourceEncoding == Encoding_Ascii) - { - return ConvertToAscii(source); - } - else - { - std::string s; - - if (sourceEncoding == Encoding_Utf8) - { - // Already in UTF-8: No conversion is required, but we ensure - // the output is correctly encoded - s = boost::locale::conv::utf_to_utf(source, boost::locale::conv::skip); - } - else - { - const char* encoding = GetBoostLocaleEncoding(sourceEncoding); - s = boost::locale::conv::to_utf(source, encoding, boost::locale::conv::skip); - } - - if (hasCodeExtensions) - { - std::string t; - RemoveIso2022EscapeSequences(t, s); - return t; - } - else - { - return s; - } - } - } - catch (std::runtime_error& e) - { - // Bad input string or bad encoding - LOG(INFO) << e.what(); - return ConvertToAscii(source); - } - } -#endif - - -#if ORTHANC_ENABLE_LOCALE == 1 - std::string Toolbox::ConvertFromUtf8(const std::string& source, - Encoding targetEncoding) - { -#if ORTHANC_STATIC_ICU == 1 - if (globalIcuData_.empty()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Call Toolbox::InitializeGlobalLocale()"); - } -#endif - - // The "::skip" flag makes boost skip invalid UTF-8 - // characters. This can occur in badly-encoded DICOM files. - - try - { - if (targetEncoding == Encoding_Utf8) - { - // Already in UTF-8: No conversion is required. - return boost::locale::conv::utf_to_utf(source, boost::locale::conv::skip); - } - else if (targetEncoding == Encoding_Ascii) - { - return ConvertToAscii(source); - } - else - { - const char* encoding = GetBoostLocaleEncoding(targetEncoding); - return boost::locale::conv::from_utf(source, encoding, boost::locale::conv::skip); - } - } - catch (std::runtime_error&) - { - // Bad input string or bad encoding - return ConvertToAscii(source); - } - } -#endif - - - static bool IsAsciiCharacter(uint8_t c) - { - return (c != 0 && - c <= 127 && - (c == '\n' || !iscntrl(c))); - } - - - bool Toolbox::IsAsciiString(const void* data, - size_t size) - { - const uint8_t* p = reinterpret_cast(data); - - for (size_t i = 0; i < size; i++, p++) - { - if (!IsAsciiCharacter(*p)) - { - return false; - } - } - - return true; - } - - - bool Toolbox::IsAsciiString(const std::string& s) - { - return IsAsciiString(s.c_str(), s.size()); - } - - - std::string Toolbox::ConvertToAscii(const std::string& source) - { - std::string result; - - result.reserve(source.size() + 1); - for (size_t i = 0; i < source.size(); i++) - { - if (IsAsciiCharacter(source[i])) - { - result.push_back(source[i]); - } - } - - return result; - } - - - void Toolbox::ComputeSHA1(std::string& result, - const void* data, - size_t size) - { - boost::uuids::detail::sha1 sha1; - - if (size > 0) - { - sha1.process_bytes(data, size); - } - - unsigned int digest[5]; - - // Sanity check for the memory layout: A SHA-1 digest is 160 bits wide - assert(sizeof(unsigned int) == 4 && sizeof(digest) == (160 / 8)); - - sha1.get_digest(digest); - - result.resize(8 * 5 + 4); - sprintf(&result[0], "%08x-%08x-%08x-%08x-%08x", - digest[0], - digest[1], - digest[2], - digest[3], - digest[4]); - } - - void Toolbox::ComputeSHA1(std::string& result, - const std::string& data) - { - if (data.size() > 0) - { - ComputeSHA1(result, data.c_str(), data.size()); - } - else - { - ComputeSHA1(result, NULL, 0); - } - } - - - bool Toolbox::IsSHA1(const void* str, - size_t size) - { - if (size == 0) - { - return false; - } - - const char* start = reinterpret_cast(str); - const char* end = start + size; - - // Trim the beginning of the string - while (start < end) - { - if (*start == '\0' || - isspace(*start)) - { - start++; - } - else - { - break; - } - } - - // Trim the trailing of the string - while (start < end) - { - if (*(end - 1) == '\0' || - isspace(*(end - 1))) - { - end--; - } - else - { - break; - } - } - - if (end - start != 44) - { - return false; - } - - for (unsigned int i = 0; i < 44; i++) - { - if (i == 8 || - i == 17 || - i == 26 || - i == 35) - { - if (start[i] != '-') - return false; - } - else - { - if (!isalnum(start[i])) - return false; - } - } - - return true; - } - - - bool Toolbox::IsSHA1(const std::string& s) - { - if (s.size() == 0) - { - return false; - } - else - { - return IsSHA1(s.c_str(), s.size()); - } - } - - - std::string Toolbox::StripSpaces(const std::string& source) - { - size_t first = 0; - - while (first < source.length() && - isspace(source[first])) - { - first++; - } - - if (first == source.length()) - { - // String containing only spaces - return ""; - } - - size_t last = source.length(); - while (last > first && - isspace(source[last - 1])) - { - last--; - } - - assert(first <= last); - return source.substr(first, last - first); - } - - - static char Hex2Dec(char c) - { - return ((c >= '0' && c <= '9') ? c - '0' : - ((c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - 'A' + 10)); - } - - void Toolbox::UrlDecode(std::string& s) - { - // http://en.wikipedia.org/wiki/Percent-encoding - // http://www.w3schools.com/tags/ref_urlencode.asp - // http://stackoverflow.com/questions/154536/encode-decode-urls-in-c - - if (s.size() == 0) - { - return; - } - - size_t source = 0; - size_t target = 0; - - while (source < s.size()) - { - if (s[source] == '%' && - source + 2 < s.size() && - isalnum(s[source + 1]) && - isalnum(s[source + 2])) - { - s[target] = (Hex2Dec(s[source + 1]) << 4) | Hex2Dec(s[source + 2]); - source += 3; - target += 1; - } - else - { - if (s[source] == '+') - s[target] = ' '; - else - s[target] = s[source]; - - source++; - target++; - } - } - - s.resize(target); - } - - - Endianness Toolbox::DetectEndianness() - { - // http://sourceforge.net/p/predef/wiki/Endianness/ - - uint32_t bufferView; - - uint8_t* buffer = reinterpret_cast(&bufferView); - - buffer[0] = 0x00; - buffer[1] = 0x01; - buffer[2] = 0x02; - buffer[3] = 0x03; - - switch (bufferView) - { - case 0x00010203: - return Endianness_Big; - - case 0x03020100: - return Endianness_Little; - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - std::string Toolbox::WildcardToRegularExpression(const std::string& source) - { - // TODO - Speed up this with a regular expression - - std::string result = source; - - // Escape all special characters - boost::replace_all(result, "\\", "\\\\"); - boost::replace_all(result, "^", "\\^"); - boost::replace_all(result, ".", "\\."); - boost::replace_all(result, "$", "\\$"); - boost::replace_all(result, "|", "\\|"); - boost::replace_all(result, "(", "\\("); - boost::replace_all(result, ")", "\\)"); - boost::replace_all(result, "[", "\\["); - boost::replace_all(result, "]", "\\]"); - boost::replace_all(result, "+", "\\+"); - boost::replace_all(result, "/", "\\/"); - boost::replace_all(result, "{", "\\{"); - boost::replace_all(result, "}", "\\}"); - - // Convert wildcards '*' and '?' to their regex equivalents - boost::replace_all(result, "?", "."); - boost::replace_all(result, "*", ".*"); - - return result; - } - - - void Toolbox::TokenizeString(std::vector& result, - const std::string& value, - char separator) - { - size_t countSeparators = 0; - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == separator) - { - countSeparators++; - } - } - - result.clear(); - result.reserve(countSeparators + 1); - - std::string currentItem; - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == separator) - { - result.push_back(currentItem); - currentItem.clear(); - } - else - { - currentItem.push_back(value[i]); - } - } - - result.push_back(currentItem); - } - - -#if ORTHANC_ENABLE_PUGIXML == 1 - class ChunkedBufferWriter : public pugi::xml_writer - { - private: - ChunkedBuffer buffer_; - - public: - virtual void write(const void *data, size_t size) - { - if (size > 0) - { - buffer_.AddChunk(reinterpret_cast(data), size); - } - } - - void Flatten(std::string& s) - { - buffer_.Flatten(s); - } - }; - - - static void JsonToXmlInternal(pugi::xml_node& target, - const Json::Value& source, - const std::string& arrayElement) - { - // http://jsoncpp.sourceforge.net/value_8h_source.html#l00030 - - switch (source.type()) - { - case Json::nullValue: - { - target.append_child(pugi::node_pcdata).set_value("null"); - break; - } - - case Json::intValue: - { - std::string s = boost::lexical_cast(source.asInt()); - target.append_child(pugi::node_pcdata).set_value(s.c_str()); - break; - } - - case Json::uintValue: - { - std::string s = boost::lexical_cast(source.asUInt()); - target.append_child(pugi::node_pcdata).set_value(s.c_str()); - break; - } - - case Json::realValue: - { - std::string s = boost::lexical_cast(source.asFloat()); - target.append_child(pugi::node_pcdata).set_value(s.c_str()); - break; - } - - case Json::stringValue: - { - target.append_child(pugi::node_pcdata).set_value(source.asString().c_str()); - break; - } - - case Json::booleanValue: - { - target.append_child(pugi::node_pcdata).set_value(source.asBool() ? "true" : "false"); - break; - } - - case Json::arrayValue: - { - for (Json::Value::ArrayIndex i = 0; i < source.size(); i++) - { - pugi::xml_node node = target.append_child(); - node.set_name(arrayElement.c_str()); - JsonToXmlInternal(node, source[i], arrayElement); - } - break; - } - - case Json::objectValue: - { - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - pugi::xml_node node = target.append_child(); - node.set_name(members[i].c_str()); - JsonToXmlInternal(node, source[members[i]], arrayElement); - } - - break; - } - - default: - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - void Toolbox::JsonToXml(std::string& target, - const Json::Value& source, - const std::string& rootElement, - const std::string& arrayElement) - { - pugi::xml_document doc; - - pugi::xml_node n = doc.append_child(rootElement.c_str()); - JsonToXmlInternal(n, source, arrayElement); - - pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); - decl.append_attribute("version").set_value("1.0"); - decl.append_attribute("encoding").set_value("utf-8"); - - XmlToString(target, doc); - } - - void Toolbox::XmlToString(std::string& target, - const pugi::xml_document& source) - { - ChunkedBufferWriter writer; - source.save(writer, " ", pugi::format_default, pugi::encoding_utf8); - writer.Flatten(target); - } -#endif - - - - bool Toolbox::IsInteger(const std::string& str) - { - std::string s = StripSpaces(str); - - if (s.size() == 0) - { - return false; - } - - size_t pos = 0; - if (s[0] == '-') - { - if (s.size() == 1) - { - return false; - } - - pos = 1; - } - - while (pos < s.size()) - { - if (!isdigit(s[pos])) - { - return false; - } - - pos++; - } - - return true; - } - - - void Toolbox::CopyJsonWithoutComments(Json::Value& target, - const Json::Value& source) - { - switch (source.type()) - { - case Json::nullValue: - target = Json::nullValue; - break; - - case Json::intValue: - target = source.asInt64(); - break; - - case Json::uintValue: - target = source.asUInt64(); - break; - - case Json::realValue: - target = source.asDouble(); - break; - - case Json::stringValue: - target = source.asString(); - break; - - case Json::booleanValue: - target = source.asBool(); - break; - - case Json::arrayValue: - { - target = Json::arrayValue; - for (Json::Value::ArrayIndex i = 0; i < source.size(); i++) - { - Json::Value& item = target.append(Json::nullValue); - CopyJsonWithoutComments(item, source[i]); - } - - break; - } - - case Json::objectValue: - { - target = Json::objectValue; - Json::Value::Members members = source.getMemberNames(); - for (Json::Value::ArrayIndex i = 0; i < members.size(); i++) - { - const std::string item = members[i]; - CopyJsonWithoutComments(target[item], source[item]); - } - - break; - } - - default: - break; - } - } - - - bool Toolbox::StartsWith(const std::string& str, - const std::string& prefix) - { - if (str.size() < prefix.size()) - { - return false; - } - else - { - return str.compare(0, prefix.size(), prefix) == 0; - } - } - - - static bool IsUnreservedCharacter(char c) - { - // This function checks whether "c" is an unserved character - // wrt. an URI percent-encoding - // https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding%5Fin%5Fa%5FURI - - return ((c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - (c >= '0' && c <= '9') || - c == '-' || - c == '_' || - c == '.' || - c == '~'); - } - - void Toolbox::UriEncode(std::string& target, - const std::string& source) - { - // Estimate the length of the percent-encoded URI - size_t length = 0; - - for (size_t i = 0; i < source.size(); i++) - { - if (IsUnreservedCharacter(source[i])) - { - length += 1; - } - else - { - // This character must be percent-encoded - length += 3; - } - } - - target.clear(); - target.reserve(length); - - for (size_t i = 0; i < source.size(); i++) - { - if (IsUnreservedCharacter(source[i])) - { - target.push_back(source[i]); - } - else - { - // This character must be percent-encoded - uint8_t byte = static_cast(source[i]); - uint8_t a = byte >> 4; - uint8_t b = byte & 0x0f; - - target.push_back('%'); - target.push_back(a < 10 ? a + '0' : a - 10 + 'A'); - target.push_back(b < 10 ? b + '0' : b - 10 + 'A'); - } - } - } - - - static bool HasField(const Json::Value& json, - const std::string& key, - Json::ValueType expectedType) - { - if (json.type() != Json::objectValue || - !json.isMember(key)) - { - return false; - } - else if (json[key].type() == expectedType) - { - return true; - } - else - { - throw OrthancException(ErrorCode_BadParameterType); - } - } - - - std::string Toolbox::GetJsonStringField(const Json::Value& json, - const std::string& key, - const std::string& defaultValue) - { - if (HasField(json, key, Json::stringValue)) - { - return json[key].asString(); - } - else - { - return defaultValue; - } - } - - - bool Toolbox::GetJsonBooleanField(const ::Json::Value& json, - const std::string& key, - bool defaultValue) - { - if (HasField(json, key, Json::booleanValue)) - { - return json[key].asBool(); - } - else - { - return defaultValue; - } - } - - - int Toolbox::GetJsonIntegerField(const ::Json::Value& json, - const std::string& key, - int defaultValue) - { - if (HasField(json, key, Json::intValue)) - { - return json[key].asInt(); - } - else - { - return defaultValue; - } - } - - - unsigned int Toolbox::GetJsonUnsignedIntegerField(const ::Json::Value& json, - const std::string& key, - unsigned int defaultValue) - { - int v = GetJsonIntegerField(json, key, defaultValue); - - if (v < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return static_cast(v); - } - } - - - bool Toolbox::IsUuid(const std::string& str) - { - if (str.size() != 36) - { - return false; - } - - for (size_t i = 0; i < str.length(); i++) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - if (str[i] != '-') - return false; - } - else - { - if (!isalnum(str[i])) - return false; - } - } - - return true; - } - - - bool Toolbox::StartsWithUuid(const std::string& str) - { - if (str.size() < 36) - { - return false; - } - - if (str.size() == 36) - { - return IsUuid(str); - } - - assert(str.size() > 36); - if (!isspace(str[36])) - { - return false; - } - - return IsUuid(str.substr(0, 36)); - } - - -#if ORTHANC_ENABLE_LOCALE == 1 - static std::unique_ptr globalLocale_; - - static bool SetGlobalLocale(const char* locale) - { - try - { - if (locale == NULL) - { - LOG(WARNING) << "Falling back to system-wide default locale"; - globalLocale_.reset(new std::locale()); - } - else - { - LOG(INFO) << "Using locale: \"" << locale << "\" for case-insensitive comparison of strings"; - globalLocale_.reset(new std::locale(locale)); - } - } - catch (std::runtime_error& e) - { - LOG(ERROR) << "Cannot set globale locale to " - << (locale ? std::string(locale) : "(null)") - << ": " << e.what(); - globalLocale_.reset(NULL); - } - - return (globalLocale_.get() != NULL); - } - - - static void InitializeIcu() - { -#if ORTHANC_STATIC_ICU == 1 - if (globalIcuData_.empty()) - { - LOG(INFO) << "Setting up the ICU common data"; - - GzipCompressor compressor; - compressor.Uncompress(globalIcuData_, - EmbeddedResources::GetFileResourceBuffer(EmbeddedResources::LIBICU_DATA), - EmbeddedResources::GetFileResourceSize(EmbeddedResources::LIBICU_DATA)); - - std::string md5; - Toolbox::ComputeMD5(md5, globalIcuData_); - - if (md5 != ORTHANC_ICU_DATA_MD5 || - globalIcuData_.empty()) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot decode the ICU common data"); - } - - // "ICU data is designed to be 16-aligned" - // http://userguide.icu-project.org/icudata#TOC-Alignment - - { - static const size_t ALIGN = 16; - - UErrorCode status = U_ZERO_ERROR; - - if (reinterpret_cast(globalIcuData_.c_str()) % ALIGN == 0) - { - // Data is already properly aligned - udata_setCommonData(globalIcuData_.c_str(), &status); - } - else - { - std::string aligned; - aligned.resize(globalIcuData_.size() + ALIGN - 1); - - intptr_t offset = reinterpret_cast(aligned.c_str()) % ALIGN; - if (offset != 0) - { - offset = ALIGN - offset; - } - - if (offset + globalIcuData_.size() > aligned.size()) - { - throw OrthancException(ErrorCode_InternalError, "Cannot align on 16-bytes boundary"); - } - - // We don't use "memcpy()", as it expects its data to be aligned - const uint8_t* p = reinterpret_cast(&globalIcuData_[0]); - uint8_t* q = reinterpret_cast(&aligned[0]) + offset; - for (size_t i = 0; i < globalIcuData_.size(); i++, p++, q++) - { - *q = *p; - } - - globalIcuData_.swap(aligned); - - const uint8_t* data = reinterpret_cast(globalIcuData_.c_str()) + offset; - - if (reinterpret_cast(data) % ALIGN != 0) - { - throw OrthancException(ErrorCode_InternalError, "Cannot align on 16-bytes boundary"); - } - else - { - udata_setCommonData(data, &status); - } - } - - if (status != U_ZERO_ERROR) - { - throw OrthancException(ErrorCode_InternalError, "Cannot initialize ICU"); - } - } - - if (Toolbox::DetectEndianness() != Endianness_Little) - { - // TODO - The data table must be swapped (uint16_t) - throw OrthancException(ErrorCode_NotImplemented); - } - - // "First-use of ICU from a single thread before the - // multi-threaded use of ICU begins", to make sure everything is - // properly initialized (should not be mandatory in our - // case). We let boost handle calls to "u_init()" and "u_cleanup()". - // http://userguide.icu-project.org/design#TOC-ICU-Initialization-and-Termination - uloc_getDefault(); - } -#endif - } - - void Toolbox::InitializeGlobalLocale(const char* locale) - { - InitializeIcu(); - -#if defined(__unix__) && ORTHANC_SANDBOXED != 1 - static const char* LOCALTIME = "/etc/localtime"; - - if (!SystemToolbox::IsExistingFile(LOCALTIME)) - { - // Check out file - // "boost_1_69_0/libs/locale/src/icu/time_zone.cpp": Direct - // access is made to this file if ICU is not used. Crash arises - // in Boost if the file is a symbolic link to a non-existing - // file (such as in Ubuntu 16.04 base Docker image). - throw OrthancException( - ErrorCode_InternalError, - "On UNIX-like systems, the file " + std::string(LOCALTIME) + - " must be present on the filesystem (install \"tzdata\" package on Debian)"); - } -#endif - - // Make Orthanc use English, United States locale - // Linux: use "en_US.UTF-8" - // Windows: use "" - // Wine: use NULL - -#if defined(__MINGW32__) - // Visibly, there is no support of locales in MinGW yet - // http://mingw.5.n7.nabble.com/How-to-use-std-locale-global-with-MinGW-correct-td33048.html - static const char* DEFAULT_LOCALE = NULL; -#elif defined(_WIN32) - // For Windows: use default locale (using "en_US" does not work) - static const char* DEFAULT_LOCALE = ""; -#else - // For Linux & cie - static const char* DEFAULT_LOCALE = "en_US.UTF-8"; -#endif - - bool ok; - - if (locale == NULL) - { - ok = SetGlobalLocale(DEFAULT_LOCALE); - -#if defined(__MINGW32__) - LOG(WARNING) << "This is a MinGW build, case-insensitive comparison of " - << "strings with accents will not work outside of Wine"; -#endif - } - else - { - ok = SetGlobalLocale(locale); - } - - if (!ok && - !SetGlobalLocale(NULL)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot initialize global locale"); - } - - } - - - void Toolbox::FinalizeGlobalLocale() - { - globalLocale_.reset(); - } - - - std::string Toolbox::ToUpperCaseWithAccents(const std::string& source) - { - bool error = (globalLocale_.get() == NULL); - -#if ORTHANC_STATIC_ICU == 1 - if (globalIcuData_.empty()) - { - error = true; - } -#endif - - if (error) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "No global locale was set, call Toolbox::InitializeGlobalLocale()"); - } - - /** - * A few notes about locales: - * - * (1) We don't use "case folding": - * http://www.boost.org/doc/libs/1_64_0/libs/locale/doc/html/conversions.html - * - * Characters are made uppercase one by one. This is because, in - * static builds, we are using iconv, which is visibly not - * supported correctly (TODO: Understand why). Case folding seems - * to be working correctly if using the default backend under - * Linux (ICU or POSIX?). If one wishes to use case folding, one - * would use: - * - * boost::locale::generator gen; - * std::locale::global(gen(DEFAULT_LOCALE)); - * return boost::locale::to_upper(source); - * - * (2) The function "boost::algorithm::to_upper_copy" does not - * make use of the "std::locale::global()". We therefore create a - * global variable "globalLocale_". - * - * (3) The variant of "boost::algorithm::to_upper_copy()" that - * uses std::string does not work properly. We need to apply it - * one wide strings (std::wstring). This explains the two calls to - * "utf_to_utf" in order to convert to/from std::wstring. - **/ - - std::wstring w = boost::locale::conv::utf_to_utf(source, boost::locale::conv::skip); - w = boost::algorithm::to_upper_copy(w, *globalLocale_); - return boost::locale::conv::utf_to_utf(w, boost::locale::conv::skip); - } -#endif - - - -#if ORTHANC_ENABLE_SSL == 0 - /** - * OpenSSL is disabled - **/ - void Toolbox::InitializeOpenSsl() - { - } - - void Toolbox::FinalizeOpenSsl() - { - } - - -#elif (ORTHANC_ENABLE_SSL == 1 && \ - OPENSSL_VERSION_NUMBER < 0x10100000L) - /** - * OpenSSL < 1.1.0 - **/ - void Toolbox::InitializeOpenSsl() - { - // https://wiki.openssl.org/index.php/Library_Initialization - SSL_library_init(); - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); - } - - void Toolbox::FinalizeOpenSsl() - { - // Finalize OpenSSL - // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup -#ifdef FIPS_mode_set - FIPS_mode_set(0); -#endif - -#if !defined(OPENSSL_NO_ENGINE) - ENGINE_cleanup(); -#endif - - CONF_modules_unload(1); - EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); - ERR_free_strings(); - } - - -#elif (ORTHANC_ENABLE_SSL == 1 && \ - OPENSSL_VERSION_NUMBER >= 0x10100000L) - /** - * OpenSSL >= 1.1.0. In this case, the initialization is - * automatically done by the functions of OpenSSL. - * https://wiki.openssl.org/index.php/Library_Initialization - **/ - void Toolbox::InitializeOpenSsl() - { - } - - void Toolbox::FinalizeOpenSsl() - { - } - -#else -# error "Support your platform here" -#endif - - - - std::string Toolbox::GenerateUuid() - { -#ifdef WIN32 - UUID uuid; - UuidCreate ( &uuid ); - - unsigned char * str; - UuidToStringA ( &uuid, &str ); - - std::string s( ( char* ) str ); - - RpcStringFreeA ( &str ); -#else - uuid_t uuid; - uuid_generate_random ( uuid ); - char s[37]; - uuid_unparse ( uuid, s ); -#endif - return s; - } - - - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - - class VariableFormatter - { - public: - typedef std::map Dictionary; - - private: - const Dictionary& dictionary_; - - public: - VariableFormatter(const Dictionary& dictionary) : - dictionary_(dictionary) - { - } - - template - Out operator()(const boost::smatch& what, - Out out) const - { - if (!what[1].str().empty()) - { - // Variable without a default value - Dictionary::const_iterator found = dictionary_.find(what[1]); - - if (found != dictionary_.end()) - { - const std::string& value = found->second; - out = std::copy(value.begin(), value.end(), out); - } - } - else - { - // Variable with a default value - std::string key; - std::string defaultValue; - - if (!what[2].str().empty()) - { - key = what[2].str(); - defaultValue = what[3].str(); - } - else if (!what[4].str().empty()) - { - key = what[4].str(); - defaultValue = what[5].str(); - } - else if (!what[6].str().empty()) - { - key = what[6].str(); - defaultValue = what[7].str(); - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - - Dictionary::const_iterator found = dictionary_.find(key); - - if (found == dictionary_.end()) - { - out = std::copy(defaultValue.begin(), defaultValue.end(), out); - } - else - { - const std::string& value = found->second; - out = std::copy(value.begin(), value.end(), out); - } - } - - return out; - } - }; - } - - - std::string Toolbox::SubstituteVariables(const std::string& source, - const std::map& dictionary) - { - const boost::regex pattern("\\$\\{([^:]*?)\\}|" // ${what[1]} - "\\$\\{([^:]*?):-([^'\"]*?)\\}|" // ${what[2]:-what[3]} - "\\$\\{([^:]*?):-\"([^\"]*?)\"\\}|" // ${what[4]:-"what[5]"} - "\\$\\{([^:]*?):-'([^']*?)'\\}"); // ${what[6]:-'what[7]'} - - VariableFormatter formatter(dictionary); - - return boost::regex_replace(source, pattern, formatter); - } - - - namespace Iso2022 - { - /** - Returns whether the string s contains a single-byte control message - at index i - **/ - static inline bool IsControlMessage1(const std::string& s, size_t i) - { - if (i < s.size()) - { - char c = s[i]; - return - (c == '\x0f') || // Locking shift zero - (c == '\x0e'); // Locking shift one - } - else - { - return false; - } - } - - /** - Returns whether the string s contains a double-byte control message - at index i - **/ - static inline size_t IsControlMessage2(const std::string& s, size_t i) - { - if (i + 1 < s.size()) - { - char c1 = s[i]; - char c2 = s[i + 1]; - return (c1 == 0x1b) && ( - (c2 == '\x6e') || // Locking shift two - (c2 == '\x6f') || // Locking shift three - (c2 == '\x4e') || // Single shift two (alt) - (c2 == '\x4f') || // Single shift three (alt) - (c2 == '\x7c') || // Locking shift three right - (c2 == '\x7d') || // Locking shift two right - (c2 == '\x7e') // Locking shift one right - ); - } - else - { - return false; - } - } - - /** - Returns whether the string s contains a triple-byte control message - at index i - **/ - static inline size_t IsControlMessage3(const std::string& s, size_t i) - { - if (i + 2 < s.size()) - { - char c1 = s[i]; - char c2 = s[i + 1]; - char c3 = s[i + 2]; - return ((c1 == '\x8e' && c2 == 0x1b && c3 == '\x4e') || - (c1 == '\x8f' && c2 == 0x1b && c3 == '\x4f')); - } - else - { - return false; - } - } - - /** - This function returns true if the index i in the supplied string s: - - is valid - - contains the c character - This function returns false otherwise. - **/ - static inline bool TestCharValue( - const std::string& s, size_t i, char c) - { - if (i < s.size()) - return s[i] == c; - else - return false; - } - - /** - This function returns true if the index i in the supplied string s: - - is valid - - has a c character that is >= cMin and <= cMax (included) - This function returns false otherwise. - **/ - static inline bool TestCharRange( - const std::string& s, size_t i, char cMin, char cMax) - { - if (i < s.size()) - return (s[i] >= cMin) && (s[i] <= cMax); - else - return false; - } - - /** - This function returns the total length in bytes of the escape sequence - located in string s at index i, if there is one, or 0 otherwise. - **/ - static inline size_t GetEscapeSequenceLength(const std::string& s, size_t i) - { - if (TestCharValue(s, i, 0x1b)) - { - size_t j = i+1; - - // advance reading cursor while we are in a sequence - while (TestCharRange(s, j, '\x20', '\x2f')) - ++j; - - // check there is a valid termination byte AND we're long enough (there - // must be at least one byte between 0x20 and 0x2f - if (TestCharRange(s, j, '\x30', '\x7f') && (j - i) >= 2) - return j - i + 1; - else - return 0; - } - else - return 0; - } - } - - - - /** - This function will strip all ISO/IEC 2022 control codes and escape - sequences. - Please see https://en.wikipedia.org/wiki/ISO/IEC_2022 (as of 2019-02) - for a list of those. - - Please note that this operation is potentially destructive, because - it removes the character set information from the byte stream. - - However, in the case where the encoding is unique, then suppressing - the escape sequences allows to provide us with a clean string after - conversion to utf-8 with boost. - **/ - void Toolbox::RemoveIso2022EscapeSequences(std::string& dest, const std::string& src) - { - // we need AT MOST the same size as the source string in the output - dest.clear(); - if (dest.capacity() < src.size()) - dest.reserve(src.size()); - - size_t i = 0; - - // uint8_t view to the string - while (i < src.size()) - { - size_t j = i; - - // The i index will only be incremented if a message is detected - // in that case, the message is skipped and the index is set to the - // next position to read - if (Iso2022::IsControlMessage1(src, i)) - i += 1; - else if (Iso2022::IsControlMessage2(src, i)) - i += 2; - else if (Iso2022::IsControlMessage3(src, i)) - i += 3; - else - i += Iso2022::GetEscapeSequenceLength(src, i); - - // if the index was NOT incremented, this means there was no message at - // this location: we then may copy the character at this index and - // increment the index to point to the next read position - if (j == i) - { - dest.push_back(src[i]); - i++; - } - } - } - - - void Toolbox::Utf8ToUnicodeCharacter(uint32_t& unicode, - size_t& length, - const std::string& utf8, - size_t position) - { - // https://en.wikipedia.org/wiki/UTF-8 - - static const uint8_t MASK_IS_1_BYTE = 0x80; // printf '0x%x\n' "$((2#10000000))" - static const uint8_t TEST_IS_1_BYTE = 0x00; - - static const uint8_t MASK_IS_2_BYTES = 0xe0; // printf '0x%x\n' "$((2#11100000))" - static const uint8_t TEST_IS_2_BYTES = 0xc0; // printf '0x%x\n' "$((2#11000000))" - - static const uint8_t MASK_IS_3_BYTES = 0xf0; // printf '0x%x\n' "$((2#11110000))" - static const uint8_t TEST_IS_3_BYTES = 0xe0; // printf '0x%x\n' "$((2#11100000))" - - static const uint8_t MASK_IS_4_BYTES = 0xf8; // printf '0x%x\n' "$((2#11111000))" - static const uint8_t TEST_IS_4_BYTES = 0xf0; // printf '0x%x\n' "$((2#11110000))" - - static const uint8_t MASK_CONTINUATION = 0xc0; // printf '0x%x\n' "$((2#11000000))" - static const uint8_t TEST_CONTINUATION = 0x80; // printf '0x%x\n' "$((2#10000000))" - - if (position >= utf8.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - assert(sizeof(uint8_t) == sizeof(char)); - const uint8_t* buffer = reinterpret_cast(utf8.c_str()) + position; - - if ((buffer[0] & MASK_IS_1_BYTE) == TEST_IS_1_BYTE) - { - length = 1; - unicode = buffer[0] & ~MASK_IS_1_BYTE; - } - else if ((buffer[0] & MASK_IS_2_BYTES) == TEST_IS_2_BYTES && - position + 1 < utf8.size() && - (buffer[1] & MASK_CONTINUATION) == TEST_CONTINUATION) - { - length = 2; - uint32_t a = buffer[0] & ~MASK_IS_2_BYTES; - uint32_t b = buffer[1] & ~MASK_CONTINUATION; - unicode = (a << 6) | b; - } - else if ((buffer[0] & MASK_IS_3_BYTES) == TEST_IS_3_BYTES && - position + 2 < utf8.size() && - (buffer[1] & MASK_CONTINUATION) == TEST_CONTINUATION && - (buffer[2] & MASK_CONTINUATION) == TEST_CONTINUATION) - { - length = 3; - uint32_t a = buffer[0] & ~MASK_IS_3_BYTES; - uint32_t b = buffer[1] & ~MASK_CONTINUATION; - uint32_t c = buffer[2] & ~MASK_CONTINUATION; - unicode = (a << 12) | (b << 6) | c; - } - else if ((buffer[0] & MASK_IS_4_BYTES) == TEST_IS_4_BYTES && - position + 3 < utf8.size() && - (buffer[1] & MASK_CONTINUATION) == TEST_CONTINUATION && - (buffer[2] & MASK_CONTINUATION) == TEST_CONTINUATION && - (buffer[3] & MASK_CONTINUATION) == TEST_CONTINUATION) - { - length = 4; - uint32_t a = buffer[0] & ~MASK_IS_4_BYTES; - uint32_t b = buffer[1] & ~MASK_CONTINUATION; - uint32_t c = buffer[2] & ~MASK_CONTINUATION; - uint32_t d = buffer[3] & ~MASK_CONTINUATION; - unicode = (a << 18) | (b << 12) | (c << 6) | d; - } - else - { - // This is not a valid UTF-8 encoding - throw OrthancException(ErrorCode_BadFileFormat, "Invalid UTF-8 string"); - } - } - - - std::string Toolbox::LargeHexadecimalToDecimal(const std::string& hex) - { - /** - * NB: Focus of the code below is *not* efficiency, but - * readability! - **/ - - for (size_t i = 0; i < hex.size(); i++) - { - const char c = hex[i]; - if (!((c >= 'A' && c <= 'F') || - (c >= 'a' && c <= 'f') || - (c >= '0' && c <= '9'))) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, - "Not an hexadecimal number"); - } - } - - std::vector decimal; - decimal.push_back(0); - - for (size_t i = 0; i < hex.size(); i++) - { - uint8_t hexDigit = static_cast(Hex2Dec(hex[i])); - assert(hexDigit <= 15); - - for (size_t j = 0; j < decimal.size(); j++) - { - uint8_t val = static_cast(decimal[j]) * 16 + hexDigit; // Maximum: 9 * 16 + 15 - assert(val <= 159 /* == 9 * 16 + 15 */); - - decimal[j] = val % 10; - hexDigit = val / 10; - assert(hexDigit <= 15 /* == 159 / 10 */); - } - - while (hexDigit > 0) - { - decimal.push_back(hexDigit % 10); - hexDigit /= 10; - } - } - - size_t start = 0; - while (start < decimal.size() && - decimal[start] == '0') - { - start++; - } - - std::string s; - s.reserve(decimal.size() - start); - - for (size_t i = decimal.size(); i > start; i--) - { - s.push_back(decimal[i - 1] + '0'); - } - - return s; - } - - - std::string Toolbox::GenerateDicomPrivateUniqueIdentifier() - { - /** - * REFERENCE: "Creating a Privately Defined Unique Identifier - * (Informative)" / "UUID Derived UID" - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part05/sect_B.2.html - * https://stackoverflow.com/a/46316162/881731 - **/ - - std::string uuid = GenerateUuid(); - assert(IsUuid(uuid) && uuid.size() == 36); - - /** - * After removing the four dashes ("-") out of the 36-character - * UUID, we get a large hexadecimal number with 32 characters, - * each of those characters lying in the range [0,16[. The large - * number is thus in the [0,16^32[ = [0,256^16[ range. This number - * has a maximum of 39 decimal digits, as can be seen in Python: - * - * # python -c 'import math; print(math.log(16**32))/math.log(10))' - * 38.531839445 - * - * We now to convert the large hexadecimal number to a decimal - * number with up to 39 digits, remove the leading zeros, then - * prefix it with "2.25." - **/ - - // Remove the dashes - std::string hex = (uuid.substr(0, 8) + - uuid.substr(9, 4) + - uuid.substr(14, 4) + - uuid.substr(19, 4) + - uuid.substr(24, 12)); - assert(hex.size() == 32); - - return "2.25." + LargeHexadecimalToDecimal(hex); - } -} - - - -OrthancLinesIterator* OrthancLinesIterator_Create(const std::string& content) -{ - return reinterpret_cast(new Orthanc::Toolbox::LinesIterator(content)); -} - - -bool OrthancLinesIterator_GetLine(std::string& target, - const OrthancLinesIterator* iterator) -{ - if (iterator != NULL) - { - return reinterpret_cast(iterator)->GetLine(target); - } - else - { - return false; - } -} - - -void OrthancLinesIterator_Next(OrthancLinesIterator* iterator) -{ - if (iterator != NULL) - { - reinterpret_cast(iterator)->Next(); - } -} - - -void OrthancLinesIterator_Free(OrthancLinesIterator* iterator) -{ - if (iterator != NULL) - { - delete reinterpret_cast(iterator); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/Toolbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,287 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "Enumerations.h" - -#include -#include -#include -#include - - -#if !defined(ORTHANC_ENABLE_BASE64) -# error The macro ORTHANC_ENABLE_BASE64 must be defined -#endif - -#if !defined(ORTHANC_ENABLE_LOCALE) -# error The macro ORTHANC_ENABLE_LOCALE must be defined -#endif - -#if !defined(ORTHANC_ENABLE_MD5) -# error The macro ORTHANC_ENABLE_MD5 must be defined -#endif - -#if !defined(ORTHANC_ENABLE_PUGIXML) -# error The macro ORTHANC_ENABLE_PUGIXML must be defined -#endif - - -/** - * NOTE: GUID vs. UUID - * The simple answer is: no difference, they are the same thing. Treat - * them as a 16 byte (128 bits) value that is used as a unique - * value. In Microsoft-speak they are called GUIDs, but call them - * UUIDs when not using Microsoft-speak. - * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid - **/ - - -#if ORTHANC_ENABLE_PUGIXML == 1 -# include -#endif - - -namespace Orthanc -{ - typedef std::vector UriComponents; - - class NullType - { - }; - - namespace Toolbox - { - class LinesIterator - { - private: - const std::string& content_; - size_t lineStart_; - size_t lineEnd_; - - void FindEndOfLine(); - - public: - LinesIterator(const std::string& content); - - bool GetLine(std::string& target) const; - - void Next(); - }; - - - void ToUpperCase(std::string& s); // Inplace version - - void ToLowerCase(std::string& s); // Inplace version - - void ToUpperCase(std::string& result, - const std::string& source); - - void ToLowerCase(std::string& result, - const std::string& source); - - void SplitUriComponents(UriComponents& components, - const std::string& uri); - - void TruncateUri(UriComponents& target, - const UriComponents& source, - size_t fromLevel); - - bool IsChildUri(const UriComponents& baseUri, - const UriComponents& testedUri); - - std::string FlattenUri(const UriComponents& components, - size_t fromLevel = 0); - -#if ORTHANC_ENABLE_MD5 == 1 - void ComputeMD5(std::string& result, - const std::string& data); - - void ComputeMD5(std::string& result, - const void* data, - size_t size); -#endif - - void ComputeSHA1(std::string& result, - const std::string& data); - - void ComputeSHA1(std::string& result, - const void* data, - size_t size); - - bool IsSHA1(const void* str, - size_t size); - - bool IsSHA1(const std::string& s); - -#if ORTHANC_ENABLE_BASE64 == 1 - void DecodeBase64(std::string& result, - const std::string& data); - - void EncodeBase64(std::string& result, - const std::string& data); - - bool DecodeDataUriScheme(std::string& mime, - std::string& content, - const std::string& source); - - void EncodeDataUriScheme(std::string& result, - const std::string& mime, - const std::string& content); -#endif - -#if ORTHANC_ENABLE_LOCALE == 1 - std::string ConvertToUtf8(const std::string& source, - Encoding sourceEncoding, - bool hasCodeExtensions); - - std::string ConvertFromUtf8(const std::string& source, - Encoding targetEncoding); -#endif - - bool IsAsciiString(const void* data, - size_t size); - - bool IsAsciiString(const std::string& s); - - std::string ConvertToAscii(const std::string& source); - - std::string StripSpaces(const std::string& source); - - // In-place percent-decoding for URL - void UrlDecode(std::string& s); - - Endianness DetectEndianness(); - - std::string WildcardToRegularExpression(const std::string& s); - - void TokenizeString(std::vector& result, - const std::string& source, - char separator); - -#if ORTHANC_ENABLE_PUGIXML == 1 - void JsonToXml(std::string& target, - const Json::Value& source, - const std::string& rootElement = "root", - const std::string& arrayElement = "item"); -#endif - -#if ORTHANC_ENABLE_PUGIXML == 1 - void XmlToString(std::string& target, - const pugi::xml_document& source); -#endif - - bool IsInteger(const std::string& str); - - void CopyJsonWithoutComments(Json::Value& target, - const Json::Value& source); - - bool StartsWith(const std::string& str, - const std::string& prefix); - - void UriEncode(std::string& target, - const std::string& source); - - std::string GetJsonStringField(const ::Json::Value& json, - const std::string& key, - const std::string& defaultValue); - - bool GetJsonBooleanField(const ::Json::Value& json, - const std::string& key, - bool defaultValue); - - int GetJsonIntegerField(const ::Json::Value& json, - const std::string& key, - int defaultValue); - - unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json, - const std::string& key, - unsigned int defaultValue); - - bool IsUuid(const std::string& str); - - bool StartsWithUuid(const std::string& str); - -#if ORTHANC_ENABLE_LOCALE == 1 - void InitializeGlobalLocale(const char* locale); - - void FinalizeGlobalLocale(); - - std::string ToUpperCaseWithAccents(const std::string& source); -#endif - - void InitializeOpenSsl(); - - void FinalizeOpenSsl(); - - std::string GenerateUuid(); - - std::string SubstituteVariables(const std::string& source, - const std::map& dictionary); - - void RemoveIso2022EscapeSequences(std::string& dest, - const std::string& src); - - void Utf8ToUnicodeCharacter(uint32_t& unicode, - size_t& utf8Length, - const std::string& utf8, - size_t position); - - std::string LargeHexadecimalToDecimal(const std::string& hex); - - // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part05/sect_B.2.html - std::string GenerateDicomPrivateUniqueIdentifier(); - } -} - - - - -/** - * The plain C, opaque data structure "OrthancLinesIterator" is a thin - * wrapper around Orthanc::Toolbox::LinesIterator, and is only used by - * "../Resources/WebAssembly/dcdict.cc", in order to avoid code - * duplication - **/ - -struct OrthancLinesIterator; - -OrthancLinesIterator* OrthancLinesIterator_Create(const std::string& content); - -bool OrthancLinesIterator_GetLine(std::string& target, - const OrthancLinesIterator* iterator); - -void OrthancLinesIterator_Next(OrthancLinesIterator* iterator); - -void OrthancLinesIterator_Free(OrthancLinesIterator* iterator); diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,585 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeaders.h" -#include "WebServiceParameters.h" - -#include "Logging.h" -#include "OrthancException.h" -#include "SerializationToolbox.h" -#include "Toolbox.h" - -#if ORTHANC_SANDBOXED == 0 -# include "SystemToolbox.h" -#endif - -#include - -namespace Orthanc -{ - static const char* KEY_CERTIFICATE_FILE = "CertificateFile"; - static const char* KEY_CERTIFICATE_KEY_FILE = "CertificateKeyFile"; - static const char* KEY_CERTIFICATE_KEY_PASSWORD = "CertificateKeyPassword"; - static const char* KEY_HTTP_HEADERS = "HttpHeaders"; - static const char* KEY_PASSWORD = "Password"; - static const char* KEY_PKCS11 = "Pkcs11"; - static const char* KEY_URL = "Url"; - static const char* KEY_URL_2 = "URL"; - static const char* KEY_USERNAME = "Username"; - - - static bool IsReservedKey(const std::string& key) - { - return (key == KEY_CERTIFICATE_FILE || - key == KEY_CERTIFICATE_KEY_FILE || - key == KEY_CERTIFICATE_KEY_PASSWORD || - key == KEY_HTTP_HEADERS || - key == KEY_PASSWORD || - key == KEY_PKCS11 || - key == KEY_URL || - key == KEY_URL_2 || - key == KEY_USERNAME); - } - - - WebServiceParameters::WebServiceParameters() : - pkcs11Enabled_(false) - { - SetUrl("http://127.0.0.1:8042/"); - } - - - void WebServiceParameters::ClearClientCertificate() - { - certificateFile_.clear(); - certificateKeyFile_.clear(); - certificateKeyPassword_.clear(); - } - - - void WebServiceParameters::SetUrl(const std::string& url) - { - if (!Toolbox::StartsWith(url, "http://") && - !Toolbox::StartsWith(url, "https://")) - { - throw OrthancException(ErrorCode_BadFileFormat, "Bad URL: " + url); - } - - // Add trailing slash if needed - if (url[url.size() - 1] == '/') - { - url_ = url; - } - else - { - url_ = url + '/'; - } - } - - - void WebServiceParameters::ClearCredentials() - { - username_.clear(); - password_.clear(); - } - - - void WebServiceParameters::SetCredentials(const std::string& username, - const std::string& password) - { - if (username.empty() && - !password.empty()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - username_ = username; - password_ = password; - } - } - - - void WebServiceParameters::SetClientCertificate(const std::string& certificateFile, - const std::string& certificateKeyFile, - const std::string& certificateKeyPassword) - { - if (certificateFile.empty()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (certificateKeyPassword.empty()) - { - throw OrthancException( - ErrorCode_BadFileFormat, - "The password for the HTTPS certificate is not provided: " + certificateFile); - } - - certificateFile_ = certificateFile; - certificateKeyFile_ = certificateKeyFile; - certificateKeyPassword_ = certificateKeyPassword; - } - - - void WebServiceParameters::FromSimpleFormat(const Json::Value& peer) - { - assert(peer.isArray()); - - pkcs11Enabled_ = false; - ClearClientCertificate(); - - if (peer.size() != 1 && - peer.size() != 3) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - SetUrl(peer.get(0u, "").asString()); - - if (peer.size() == 1) - { - ClearCredentials(); - } - else if (peer.size() == 2) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The HTTP password is not provided"); - } - else if (peer.size() == 3) - { - SetCredentials(peer.get(1u, "").asString(), - peer.get(2u, "").asString()); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - static std::string GetStringMember(const Json::Value& peer, - const std::string& key, - const std::string& defaultValue) - { - if (!peer.isMember(key)) - { - return defaultValue; - } - else if (peer[key].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - return peer[key].asString(); - } - } - - - void WebServiceParameters::FromAdvancedFormat(const Json::Value& peer) - { - assert(peer.isObject()); - - std::string url = GetStringMember(peer, KEY_URL, ""); - if (url.empty()) - { - SetUrl(GetStringMember(peer, KEY_URL_2, "")); - } - else - { - SetUrl(url); - } - - SetCredentials(GetStringMember(peer, KEY_USERNAME, ""), - GetStringMember(peer, KEY_PASSWORD, "")); - - std::string file = GetStringMember(peer, KEY_CERTIFICATE_FILE, ""); - if (!file.empty()) - { - SetClientCertificate(file, GetStringMember(peer, KEY_CERTIFICATE_KEY_FILE, ""), - GetStringMember(peer, KEY_CERTIFICATE_KEY_PASSWORD, "")); - } - else - { - ClearClientCertificate(); - } - - if (peer.isMember(KEY_PKCS11)) - { - if (peer[KEY_PKCS11].type() == Json::booleanValue) - { - pkcs11Enabled_ = peer[KEY_PKCS11].asBool(); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - else - { - pkcs11Enabled_ = false; - } - - - headers_.clear(); - - if (peer.isMember(KEY_HTTP_HEADERS)) - { - const Json::Value& h = peer[KEY_HTTP_HEADERS]; - if (h.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - Json::Value::Members keys = h.getMemberNames(); - for (size_t i = 0; i < keys.size(); i++) - { - const Json::Value& value = h[keys[i]]; - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - headers_[keys[i]] = value.asString(); - } - } - } - } - - - userProperties_.clear(); - - const Json::Value::Members members = peer.getMemberNames(); - - for (Json::Value::Members::const_iterator it = members.begin(); - it != members.end(); ++it) - { - if (!IsReservedKey(*it)) - { - switch (peer[*it].type()) - { - case Json::stringValue: - userProperties_[*it] = peer[*it].asString(); - break; - - case Json::booleanValue: - userProperties_[*it] = peer[*it].asBool() ? "1" : "0"; - break; - - case Json::intValue: - userProperties_[*it] = boost::lexical_cast(peer[*it].asInt()); - break; - - default: - throw OrthancException(ErrorCode_BadFileFormat, - "User-defined properties associated with a Web service must be strings: " + *it); - } - } - } - } - - - void WebServiceParameters::Unserialize(const Json::Value& peer) - { - try - { - if (peer.isArray()) - { - FromSimpleFormat(peer); - } - else if (peer.isObject()) - { - FromAdvancedFormat(peer); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - catch (OrthancException&) - { - throw; - } - catch (...) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - void WebServiceParameters::ListHttpHeaders(std::set& target) const - { - target.clear(); - - for (Dictionary::const_iterator it = headers_.begin(); - it != headers_.end(); ++it) - { - target.insert(it->first); - } - } - - - bool WebServiceParameters::LookupHttpHeader(std::string& value, - const std::string& key) const - { - Dictionary::const_iterator found = headers_.find(key); - - if (found == headers_.end()) - { - return false; - } - else - { - value = found->second; - return true; - } - } - - - void WebServiceParameters::AddUserProperty(const std::string& key, - const std::string& value) - { - if (IsReservedKey(key)) - { - throw OrthancException( - ErrorCode_ParameterOutOfRange, - "Cannot use this reserved key to name an user property: " + key); - } - else - { - userProperties_[key] = value; - } - } - - - void WebServiceParameters::ListUserProperties(std::set& target) const - { - target.clear(); - - for (Dictionary::const_iterator it = userProperties_.begin(); - it != userProperties_.end(); ++it) - { - target.insert(it->first); - } - } - - - bool WebServiceParameters::LookupUserProperty(std::string& value, - const std::string& key) const - { - Dictionary::const_iterator found = userProperties_.find(key); - - if (found == userProperties_.end()) - { - return false; - } - else - { - value = found->second; - return true; - } - } - - - bool WebServiceParameters::GetBooleanUserProperty(const std::string& key, - bool defaultValue) const - { - Dictionary::const_iterator found = userProperties_.find(key); - - if (found == userProperties_.end()) - { - return defaultValue; - } - else if (found->second == "0" || - found->second == "false") - { - return false; - } - else if (found->second == "1" || - found->second == "true") - { - return true; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, "Bad value for a Boolean user property in the parameters " - "of a Web service: Property \"" + key + "\" equals: " + found->second); - } - } - - - bool WebServiceParameters::IsAdvancedFormatNeeded() const - { - return (!certificateFile_.empty() || - !certificateKeyFile_.empty() || - !certificateKeyPassword_.empty() || - pkcs11Enabled_ || - !headers_.empty() || - !userProperties_.empty()); - } - - - void WebServiceParameters::Serialize(Json::Value& value, - bool forceAdvancedFormat, - bool includePasswords) const - { - if (forceAdvancedFormat || - IsAdvancedFormatNeeded()) - { - value = Json::objectValue; - value[KEY_URL] = url_; - - if (!username_.empty() || - !password_.empty()) - { - value[KEY_USERNAME] = username_; - - if (includePasswords) - { - value[KEY_PASSWORD] = password_; - } - } - - if (!certificateFile_.empty()) - { - value[KEY_CERTIFICATE_FILE] = certificateFile_; - } - - if (!certificateKeyFile_.empty()) - { - value[KEY_CERTIFICATE_KEY_FILE] = certificateKeyFile_; - } - - if (!certificateKeyPassword_.empty() && - includePasswords) - { - value[KEY_CERTIFICATE_KEY_PASSWORD] = certificateKeyPassword_; - } - - value[KEY_PKCS11] = pkcs11Enabled_; - - value[KEY_HTTP_HEADERS] = Json::objectValue; - for (Dictionary::const_iterator it = headers_.begin(); - it != headers_.end(); ++it) - { - value[KEY_HTTP_HEADERS][it->first] = it->second; - } - - for (Dictionary::const_iterator it = userProperties_.begin(); - it != userProperties_.end(); ++it) - { - value[it->first] = it->second; - } - } - else - { - value = Json::arrayValue; - value.append(url_); - - if (!username_.empty() || - !password_.empty()) - { - value.append(username_); - value.append(includePasswords ? password_ : ""); - } - } - } - - -#if ORTHANC_SANDBOXED == 0 - void WebServiceParameters::CheckClientCertificate() const - { - if (!certificateFile_.empty()) - { - if (!SystemToolbox::IsRegularFile(certificateFile_)) - { - throw OrthancException(ErrorCode_InexistentFile, - "Cannot open certificate file: " + certificateFile_); - } - - if (!certificateKeyFile_.empty() && - !SystemToolbox::IsRegularFile(certificateKeyFile_)) - { - throw OrthancException(ErrorCode_InexistentFile, - "Cannot open key file: " + certificateKeyFile_); - } - } - } -#endif - - - void WebServiceParameters::FormatPublic(Json::Value& target) const - { - target = Json::objectValue; - - // Only return the public information identifying the destination. - // "Security"-related information such as passwords and HTTP - // headers are shown as "null" values. - target[KEY_URL] = url_; - - if (!username_.empty()) - { - target[KEY_USERNAME] = username_; - target[KEY_PASSWORD] = Json::nullValue; - } - - if (!certificateFile_.empty()) - { - target[KEY_CERTIFICATE_FILE] = certificateFile_; - target[KEY_CERTIFICATE_KEY_FILE] = Json::nullValue; - target[KEY_CERTIFICATE_KEY_PASSWORD] = Json::nullValue; - } - - target[KEY_PKCS11] = pkcs11Enabled_; - - Json::Value headers = Json::arrayValue; - - for (Dictionary::const_iterator it = headers_.begin(); - it != headers_.end(); ++it) - { - // Only list the HTTP headers, not their value - headers.append(it->first); - } - - target[KEY_HTTP_HEADERS] = headers; - - for (Dictionary::const_iterator it = userProperties_.begin(); - it != userProperties_.end(); ++it) - { - target[it->first] = it->second; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Core/WebServiceParameters.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - -#include -#include -#include -#include - -namespace Orthanc -{ - class WebServiceParameters - { - public: - typedef std::map Dictionary; - - private: - std::string url_; - std::string username_; - std::string password_; - std::string certificateFile_; - std::string certificateKeyFile_; - std::string certificateKeyPassword_; - bool pkcs11Enabled_; - Dictionary headers_; - Dictionary userProperties_; - - void FromSimpleFormat(const Json::Value& peer); - - void FromAdvancedFormat(const Json::Value& peer); - - public: - WebServiceParameters(); - - WebServiceParameters(const Json::Value& serialized) - { - Unserialize(serialized); - } - - const std::string& GetUrl() const - { - return url_; - } - - void SetUrl(const std::string& url); - - void ClearCredentials(); - - void SetCredentials(const std::string& username, - const std::string& password); - - const std::string& GetUsername() const - { - return username_; - } - - const std::string& GetPassword() const - { - return password_; - } - - void ClearClientCertificate(); - - void SetClientCertificate(const std::string& certificateFile, - const std::string& certificateKeyFile, - const std::string& certificateKeyPassword); - - const std::string& GetCertificateFile() const - { - return certificateFile_; - } - - const std::string& GetCertificateKeyFile() const - { - return certificateKeyFile_; - } - - const std::string& GetCertificateKeyPassword() const - { - return certificateKeyPassword_; - } - - void SetPkcs11Enabled(bool enabled) - { - pkcs11Enabled_ = enabled; - } - - bool IsPkcs11Enabled() const - { - return pkcs11Enabled_; - } - - void AddHttpHeader(const std::string& key, - const std::string& value) - { - headers_[key] = value; - } - - void ClearHttpHeaders() - { - headers_.clear(); - } - - const Dictionary& GetHttpHeaders() const - { - return headers_; - } - - void ListHttpHeaders(std::set& target) const; - - bool LookupHttpHeader(std::string& value, - const std::string& key) const; - - void AddUserProperty(const std::string& key, - const std::string& value); - - void ClearUserProperties() - { - userProperties_.clear(); - } - - const Dictionary& GetUserProperties() const - { - return userProperties_; - } - - void ListUserProperties(std::set& target) const; - - bool LookupUserProperty(std::string& value, - const std::string& key) const; - - bool GetBooleanUserProperty(const std::string& key, - bool defaultValue) const; - - bool IsAdvancedFormatNeeded() const; - - void Unserialize(const Json::Value& peer); - - void Serialize(Json::Value& value, - bool forceAdvancedFormat, - bool includePasswords) const; - -#if ORTHANC_SANDBOXED == 0 - void CheckClientCertificate() const; -#endif - - void FormatPublic(Json::Value& target) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/NEWS orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/NEWS --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/NEWS 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/NEWS 1970-01-01 00:00:00.000000000 +0000 @@ -1,1542 +0,0 @@ -Pending changes in the mainline -=============================== - - - -Version 1.7.0 (2020-05-22) -========================== - -General -------- - -* Support of DICOM C-GET SCP (contribution by Varian) -* DICOM transcoding over the REST API -* Transcoding from compressed to uncompressed transfer syntaxes over DICOM - C-STORE SCU (if the remote modality doesn't support compressed syntaxes) -* New configuration options related to transcoding: - "TranscodeDicomProtocol", "BuiltinDecoderTranscoderOrder", - "IngestTranscoding" and "DicomLossyTranscodingQuality" - -REST API --------- - -* API version upgraded to 7 -* Improved: - - "/instances/../modify": it is now possible to "Keep" the "SOPInstanceUID". - Note that it was already possible to "Replace" it. - - added "Timeout" parameter to every DICOM operation - - "/queries/.../answers/../retrieve": "TargetAet" not mandatory anymore - (defaults to the local AET) -* Changes: - - "/{patients|studies|series}/.../modify": New option "KeepSource" - - "/{patients|studies|series|instances}/.../modify": New option "Transcode" - - "/peers/{id}/store": New option "Transcode" - - ".../archive", ".../media", "/tools/create-media" and - "/tools/create-archive": New option "Transcode" - - "/ordered-slices": reverted the change introduced in 1.5.8 and go-back - to 1.5.7 behaviour. - -Plugins -------- - -* New functions in the SDK: - - OrthancPluginCreateDicomInstance() - - OrthancPluginCreateMemoryBuffer() - - OrthancPluginEncodeDicomWebJson2() - - OrthancPluginEncodeDicomWebXml2() - - OrthancPluginFreeDicomInstance() - - OrthancPluginGetInstanceAdvancedJson() - - OrthancPluginGetInstanceDecodedFrame() - - OrthancPluginGetInstanceDicomWebJson() - - OrthancPluginGetInstanceDicomWebXml() - - OrthancPluginGetInstanceFramesCount() - - OrthancPluginGetInstanceRawFrame() - - OrthancPluginRegisterTranscoderCallback() - - OrthancPluginSerializeDicomInstance() - - OrthancPluginTranscodeDicomInstance() -* "OrthancPluginDicomInstance" structure wrapped in "OrthancPluginCppWrapper.h" -* Allow concurrent calls to the custom image decoders provided by the plugins - -Maintenance ------------ - -* Moved the GDCM sample plugin out of the Orthanc repository as a separate plugin -* Fix missing body in "OrthancPluginHttpPost()" and "OrthancPluginHttpPut()" -* Fix issue #169 (TransferSyntaxUID change from Explicit to Implicit during C-STORE SCU) -* Fix issue #179 (deadlock in Python plugins) -* Upgraded dependencies for static builds (notably on Windows and LSB): - - openssl 1.1.1g - - -Version 1.6.1 (2020-04-21) -========================== - -REST API --------- - -* API version has been upgraded to 6 -* Added: - - "/modalities/{id}/store-straight": Synchronously send the DICOM instance in POST - body to another modality (alternative to command-line tools such as "storescu") - -Plugins -------- - -* New functions in the SDK: - - OrthancPluginRegisterIncomingDicomInstanceFilter() - - OrthancPluginGetInstanceTransferSyntaxUid() - - OrthancPluginHasInstancePixelData() - -Lua ---- - -* New "info" field in "ReceivedInstanceFilter()" callback, containing - "HasPixelData" and "TransferSyntaxUID" information - -Maintenance ------------ - -* Source code repository moved from BitBucket to self-hosted server -* Fix OpenSSL initialization on Linux Standard Base -* Fix lookup form in Orthanc Explorer (wildcards not allowed in StudyDate) -* Fix signature of "OrthancPluginRegisterStorageCommitmentScpCallback()" in plugins SDK -* Error reporting on failure while initializing SSL -* Fix unit test ParsedDicomFile.ToJsonFlags2 on big-endian architectures -* Avoid one memcpy of the DICOM buffer on "POST /instances" -* Upgraded dependencies for static builds (notably on Windows): - - civetweb 1.12 - - openssl 1.1.1f - - -Version 1.6.0 (2020-03-18) -========================== - -General -------- - -* Support of DICOM storage commitment - -REST API --------- - -* API version has been upgraded to 5 -* Added: - - "/peers/{id}/system": Test the connectivity with a remote peer - (and also retrieve its version number) - - "/tools/log-level": Access and/or change the log level without restarting Orthanc - - "/instances/{id}/frames/{frame}/rendered" and "/instances/{id}/rendered": - Render frames, taking windowing and resizing into account - - "/modalities/{...}/storage-commitment": Trigger storage commitment SCU - - "/storage-commitment/{...}": Access storage commitment reports - - "/storage-commitment/{...}/remove": Remove instances from storage commitment reports -* Improved: - - "/changes": Allow the "limit" argument to be greater than 100 - - "/instances": Support "Content-Encoding: gzip" to upload gzip-compressed DICOM files - - ".../modify" and "/tools/create-dicom": New option "PrivateCreator" for private tags - - "/modalities/{...}/store": New Boolean argument "StorageCommitment" - -Plugins -------- - -* New sample plugin: "ConnectivityChecks" -* New primitives to handle storage commitment SCP by plugins - -Lua ---- - -* New events: - - "OnDeletedPatient", "OnDeletedStudy", "OnDeletedSeries", "OnDeletedInstance": - triggered when a resource is deleted - - "OnUpdatedPatient", "OnUpdatedStudy", "OnUpdatedSeries", "OnUpdatedInstance": - triggered when an attachment or a metadata is updated - -Maintenance ------------ - -* New configuration options: "DefaultPrivateCreator" and "StorageCommitmentReportsSize" -* Support of MPEG4 transfer syntaxes in C-Store SCP -* C-FIND SCU at Instance level now sets the 0008,0052 tag to IMAGE per default (was INSTANCE). - Therefore, the "ClearCanvas" and "Dcm4Chee" modality manufacturer have now been deprecated. -* More strict C-FIND SCP wrt. the DICOM standard: Forbid wildcard - matching on some VRs, ignore main tags below the queried level -* Fix issue #65 (Logging improvements) -* Fix issue #103 ("queries/.../retrieve" API returns HTTP code 200 even on server errors) -* Fix issue #140 (Modifying private tags with REST API changes VR from LO to UN) -* Fix issue #154 (Matching against list of UID-s by C-MOVE) -* Fix issue #156 (Chunked Dicom-web transfer uses 100% CPU) -* Fix issue #165 (Boundary parameter in multipart Content-Type is too long) -* Fix issue #166 (CMake find_boost version is now broken with newer boost/cmake) -* Fix issue #167 (Job can't be cancelled - Handling of timeouts after established association) -* Fix issue #168 (Plugins can't read private tags from the configuration file) -* Upgraded dependencies for static builds (notably on Windows): - - dcmtk 3.6.5 - - openssl 1.1.1d - - jsoncpp 0.10.7 for pre-C++11 compilers - - -Version 1.5.8 (2019-10-16) -========================== - -REST API --------- - -* API version has been upgraded to 4 -* In /ordered-slices route, ignore instances without position/normal/seriesIndex, - unless there are only such instances in the series - -Maintenance ------------ - -* Security: If remote access is enabled, HTTP authentication is also - enabled by default. This modification was done to mitigate security - risks reported by independant security researcher Amitay Dan. -* Security: New configuration option "ExecuteLuaEnabled" to allow "/tools/execute-script" -* New configuration option: "HttpRequestTimeout" -* Log an explicit error if uploading an empty DICOM file using REST API -* Name of temporary files now include the process ID to ease design of scripts cleaning /tmp -* Fix compatibility of LSB binaries with Ubuntu >= 18.04 -* Fix generation of "SOP Instance UID" on split and merge -* Orthanc Explorer: include the URL search params into HTTP headers to - the REST API to ease usage of the Authorization plugin. Note that - only the 'token', 'auth-token' & 'authorization' search params are - transmitted into HTTP headers. -* Fix lost relationships between CT and RT-STRUCT during anonymization - - -Version 1.5.7 (2019-06-25) -========================== - -REST API --------- - -* API version has been upgraded to 3 -* "/modalities/{id}/query": New argument "Normalize" can be set to "false" - to bypass the automated correction of outgoing C-FIND queries -* Reporting of "ParentResources" in "DicomModalityStore" and "DicomModalityStore" jobs - -Plugins -------- - -* New functions in the SDK: - - OrthancPluginHttpClientChunkedBody(): HTTP client for POST/PUT with a chunked body - - OrthancPluginRegisterMultipartRestCallback(): HTTP server for POST/PUT with multipart body - - OrthancPluginGetTagName(): Retrieve the name of a DICOM tag from its group and element - -Maintenance ------------ - -* Orthanc now accepts "-H 'Transfer-Encoding: chunked'" option from curl -* Size of the Orthanc static binaries are reduced by compressing ICU data -* Anonymization: Preserve hierarchical relationships in (0008,1115) [] (0020,000e) -* Allow the serialization of signed 16bpp images in PAM format -* HTTP header "Accept-Encoding" is honored for streams without built-in support for compression -* The default HTTP timeout is now 60 seconds (instead of 10 seconds in previous versions) -* Allow anonymizing/modifying instances without the PatientID tag -* Fix issue #106 (Unable to export preview as jpeg from Lua script) -* Fix issue #136 (C-FIND request fails when found DICOM file does not have certain tags) -* Fix issue #137 (C-STORE fails for unknown SOP Class although server is configured to accept any) -* Fix issue #138 (POST to modalities/{name} accepts invalid characters) -* Fix issue #141 (/tools/create-dicom removes non-ASCII characters from study description) - - -Version 1.5.6 (2019-03-01) -========================== - -Orthanc Explorer ----------------- - -* If performing a Query/Retrieve operation, the default value for the - tags is set to an empty string instead of '*', which allows to match - even if the tag is not present. This allows malformed DICOM files to - be matched, even though they lack required tags such as "PatientSex" - -Maintenance ------------ - -* Enlarge the support of JSON-to-XML conversion in the REST API -* Fix missing DB transactions in some write operations -* Fix performance issue in DICOM protocol by disabling Nagle's algorithm - - -Version 1.5.5 (2019-02-25) -========================== - -General -------- - -* Support of the following multi-byte specific character sets: - - Japanese Kanji (ISO 2022 IR 87) - - Korean (ISO 2022 IR 149) - - Simplified Chinese (ISO 2022 IR 58) -* Basic support for character sets with code extensions (ISO 2022 escape sequences) - -REST API --------- - -* API version has been upgraded to 2 -* "DicomMoveScu" jobs provide the associated C-FIND answer in their "Query" public field - -Plugins -------- - -* Separation of ideographic and phonetic characters in DICOMweb JSON and XML - -Maintenance ------------ - -* Accept SOP classes: BreastProjectionXRayImageStorageForProcessing/Presentation -* More tolerance wrt. missing DICOM tags that must be returned by Orthanc C-FIND SCP -* Orthanc now interprets the "DCMDICTPATH" environment variable the same way as DCMTK -* New CMake option: "-DMSVC_MULTIPLE_PROCESSES=ON" for parallel build with Visual Studio -* Fix issue #126 (Orthanc and DCMDICTPATH) -* Fix issue #131 (C-MOVE failure due to duplicate StudyInstanceUID in the database) -* Fix issue #134 (/patient/modify gives 500, should really be 400) -* Upgraded dependencies for static builds (notably on Windows): - - boost 1.69.0 - - curl 1.64.0 - - dcmtk 3.6.4 - - e2fsprogs 1.44.5 (libuuid) - - googletest 1.8.1 - - libjpeg 9c - - libpng 1.6.36 - - openssl 1.0.2p - - pugixml 1.9 - - sqlite amalgamation 3.27.1 - - -Version 1.5.4 (2019-02-08) -========================== - -General -------- - -* New configuration options: - - "MetricsEnabled" to enable the tracking of the metrics of Orthanc - - "HttpThreadsCount" to set the number of threads in the embedded HTTP server - - "TemporaryDirectory" to set the folder containing the temporary files - -REST API --------- - -* API version has been upgraded to 1.4 -* URI "/instances/.../file" can return DICOMweb JSON or XML, depending - on the content of the "Accept" HTTP header -* New URI "/tools/metrics" to dynamically enable/disable the collection of metrics -* New URI "/tools/metrics-prometheus" to retrieve metrics using Prometheus text format -* URI "/peers?expand" provides more information about the peers - -Plugins -------- - -* New functions in the SDK: - - OrthancPluginSetMetricsValue() to set the value of a metrics - - OrthancPluginRegisterRefreshMetricsCallback() to ask to refresh metrics - - OrthancPluginEncodeDicomWebJson() to convert DICOM to "application/dicom+json" - - OrthancPluginEncodeDicomWebXml() to convert DICOM to "application/dicom+xml" -* New extensions in the database SDK: LookupResourceAndParent and GetAllMetadata - -Maintenance ------------ - -* Fix regression if calling "/tools/find" with the tag "ModalitiesInStudy" -* Fix build with unpatched versions of Civetweb (missing "mg_disable_keep_alive()") -* Fix issue #130 (Orthanc failed to start when /tmp partition was full) - - -Version 1.5.3 (2019-01-25) -========================== - -General -------- - -* New configuration option: "SaveJobs" to specify whether jobs are stored in the database - -Maintenance ------------ - -* Don't return tags whose group is below 0x0008 in C-FIND SCP answers -* Fix compatibility with DICOMweb plugin (allow multipart answers over HTTP Keep-Alive) -* Fix issue #73 (/modalities/{modalityId}/store raises 500 errors instead of 404) -* Fix issue #90 (C-Find shall match missing tags to null/empty string) -* Fix issue #119 (/patients/.../archive returns a 500 when JobsHistorySize is 0) -* Fix issue #128 (Asynchronous C-MOVE: invalid number of remaining sub-operations) - - -Version 1.5.2 (2019-01-18) -========================== - -General -------- - -* CivetWeb is now the default embedded HTTP server (instead of Mongoose) -* New configuration option: "TcpNoDelay" to disable Nagle's algorithm in HTTP server - -REST API --------- - -* API version has been upgraded to 1.3 -* More consistent handling of the "Last" field returned by the "/changes" URI - -Plugins -------- - -* New primitives to speed up databases (custom index plugins) - -Maintenance ------------ - -* Ignore tags whose group is below 0x0008 in C-FIND SCP requests -* Compatibility with DCMTK 3.6.4 -* Fix issue #21 (DICOM files missing after uploading with Firefox) -* Fix issue #32 (HTTP keep-alive is now enabled by default) -* Fix issue #58 (Patient recycling order should be defined by their received last instance) -* Fix issue #118 (Wording in Configuration.json regarding SynchronousCMove) -* Fix issue #124 (GET /studies/ID/media fails for certain dicom file) -* Fix issue #125 (Mongoose: /instances/{id} returns 500 on invalid HTTP Method) -* Fixed Orthanc Explorer on IE and Firefox: Explorer always show "too many results" - and it's therefore impossible to browse the content -* Upgraded dependencies for static and Windows builds: - - civetweb 1.11 - - -Version 1.5.1 (2018-12-20) -========================== - -General -------- - -* Optimization: On C-FIND, avoid accessing the storage area whenever possible -* New configuration option: - - "StorageAccessOnFind" to rule the access to the storage area during C-FIND - -Maintenance ------------ - -* Removal of the "AllowFindSopClassesInStudy" old configuration option -* "/tools/create-dicom" is more tolerant wrt. invalid specific character set - - -Version 1.5.0 (2018-12-10) -========================== - -General -------- - -* Possibility to restrict the allowed DICOM commands for each modality -* The Orthanc configuration file can use environment variables -* New configuration options: - - "DicomModalitiesInDatabase" to store the definitions of modalities in the database - - "OrthancPeersInDatabase" to store the definitions of Orthanc peers in the database - -Orthanc Explorer ----------------- - -* The first screen of Orthanc Explorer is now a form to do studies lookups -* Support of large databases, by limiting the results to 100 patients or studies - -REST API --------- - -* API version has been upgraded to 1.2 -* Asynchronous generation of ZIP archives and DICOM medias -* New URI: "/studies/.../merge" to merge a study -* New URI: "/studies/.../split" to split a study -* POST-ing a DICOM file to "/instances" also answers the patient/study/series ID -* GET "/modalities/?expand" now returns a JSON object instead of a JSON array -* New "Details" field in HTTP answers on error (cf. "HttpDescribeErrors" option) -* New options to URI "/queries/.../answers": "?expand" and "?simplify" -* New URIs to launch new C-FIND to explore the hierarchy of a C-FIND answer: - - "/queries/.../answers/.../query-instances" to C-FIND child instances - - "/queries/.../answers/.../query-series" to C-FIND child series - - "/queries/.../answers/.../query-studies" to C-FIND child studies -* New "DicomDiskSize" and "DicomUncompressedSize" fields in statistics about resources - -Plugins -------- - -* New functions in the SDK: - - "OrthancPluginSetHttpErrorDetails()" - - "OrthancPluginAutodetectMimeType()" - -Maintenance ------------ - -* "SynchronousCMove" is now "true" by default -* New modality manufacturer: "GE" for GE Healthcare EA and AW -* Executing a query/retrieve from the REST API now creates a job -* Fix: Closing DICOM associations after running query/retrieve from REST API -* Fix: Allow creation of MONOCHROME1 grayscale images in tools/create-dicom -* Remove invalid characters from badly-encoded UTF-8 strings (impacts PostgreSQL) -* Orthanc starts even if jobs from a previous execution cannot be unserialized -* New CMake option "ENABLE_DCMTK_LOG" to disable logging internal to DCMTK -* Fix issue 114 (Boost 1.68 doesn't support SHA-1 anymore) -* Support of "JobsHistorySize" set to zero -* Upgraded dependencies for static and Windows builds: - - boost 1.68.0 - - lua 5.3.5 - - -Version 1.4.2 (2018-09-20) -========================== - -General -------- - -* "OrthancPeers" configuration option now allows to specify HTTP headers -* New main DICOM tag: "ImageOrientationPatient" at the instance level -* New configuration options: - - "HttpVerbose" to debug outgoing HTTP connections - - "OverwriteInstances" to choose how duplicate SOPInstanceUID are handled - -Orthanc Explorer ----------------- - -* Query/retrieve: Added button for "DX" modality - -REST API --------- - -* "/tools/reconstruct" to reconstruct the main DICOM tags, the JSON summary and - the metadata of all the instances stored in Orthanc. This is a slow operation! - -Plugins -------- - -* New primitives to access Orthanc peers from plugins -* New events in change callbacks: "UpdatedPeers" and "UpdatedModalities" -* New primitives to handle jobs from plugins: "OrthancPluginSubmitJob()" - and "OrthancPluginRegisterJobsUnserializer()" - -Lua ---- - -* IncomingWorklistRequestFilter() to filter incoming C-FIND worklist queries - -Maintenance ------------ - -* Fix "/series/.../ordered-slices" in the presence of non-parallel slices -* Fix incoming DICOM C-Store filtering for JPEG-LS transfer syntaxes -* Fix OrthancPluginHttpClient() to return the HTTP status on errors -* Fix HTTPS requests to sites using a certificate encrypted with ECDSA -* Fix handling of incoming C-FIND queries containing Generic Group Length (*, 0x0000) -* Fix issue 54 (quoting multipart answers), for OsiriX compatibility through DICOMweb -* Fix issue 98 (DCMTK configuration fails with GCC 6.4.0 on Alpine) -* Fix issue 99 (PamWriter test segfaults on alpine linux with gcc 6.4.0) - - -Version 1.4.1 (2018-07-17) -========================== - -* Fix deadlock in Lua scripting -* Simplification to the "DatabaseWrapper" class - - -Version 1.4.0 (2018-07-13) -========================== - -General -------- - -* New advanced job engine -* New configuration options: - - "ConcurrentJobs": Max number of jobs that are simultaneously running - - "SynchronousCMove": Whether to run DICOM C-Move operations synchronously - - "JobsHistorySize": Max number of completed jobs that are kept in memory -* New metadata automatically computed at the instance level: - "RemoteIp", "CalledAet" and "HttpUsername" - -Orthanc Explorer ----------------- - -* New screen listing all the available studies - -REST API --------- - -* "/jobs/..." to manage the jobs from the REST API -* New option "?short" to list DICOM tags using their hexadecimal ID in: - - "/instances/.../tags?short" - - "/instances/.../header?short" - - "/{patients|studies|series}/.../instances-tags?short" - - "/{patients|studies|series}/.../shared-tags?short" - - "/{patients|studies|series|instances}/.../module?short" - - "/studies/.../module-patient?short" -* "/instances/.../tags" URI was returning only the first value of - DicomTags containing multiple numerical value. It now returns all - values in a string separated by \\ (i.e.: "1\\2\\3"). Note that, - for data already in Orthanc, you'll need to reconstruct the data by - sending a POST request to the ".../reconstruct" URI. This change - triggered an update of ORTHANC_API_VERSION from 1.0 to 1.1 -* "/instances/.../frame/../image-uint8 and friends now accepts a - "image/pam" MIME type to retrieve images in PAM format - (https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format) -* New option "?expand" to "/instances/.../metadata" - -Plugins -------- - -* New primitive in database SDK: "lookupIdentifierRange" to speed up range searches -* New function in the SDK: "OrthancPluginCheckVersionAdvanced()" - -Maintenance ------------ - -* Configuration option "LogExportedResources" is now "false" by default -* Header "OrthancCppDatabasePlugin.h" is now part of the "orthanc-databases" project -* Fix generation of DICOMDIR if PatientID is empty -* Fix issue 25 (Deadlock with Lua scripts): The event queue is now implemented for Lua -* Fix issue 94 (Instance modification should not modify FrameOfReferenceUID) -* Fix issue 77 (Lua access to REST-API is null terminated) -* Fix memory leak introduced by changeset #99116ed6f38c in Orthanc 1.3.2 -* Upgraded dependencies for static and Windows builds: - - boost 1.67.0 - - openssl 1.0.2o - - -Version 1.3.2 (2018-04-18) -========================== - -REST API --------- - -* "/system" URI returns the version of the Orthanc REST API -* "/tools/now" returns the current UTC (universal) time -* "/tools/now-local" returns the curent local time. - This was the behavior of "/tools/now" until release 1.3.1. -* Added "?expand" GET argument to "/peers" and "/modalities" routes -* New URI: "/tools/create-media-extended" to generate a DICOMDIR - archive from several resources, including additional type-3 tags -* Preservation of UID relationships while anonymizing - -Lua ---- - -* New CMake option: "-DENABLE_LUA_MODULES=ON" to enable support for - loading external Lua modules if the Lua engine is statically linked - -Plugins -------- - -* New error code: DatabaseUnavailable - -Maintenance ------------ - -* Orthanc now uses UTC (universal time) instead of local time in its database -* Fix to allow creating DICOM instances with empty Specific Character Set (0008,0005) -* Support of Linux Standard Base -* Static linking against libuuid (from e2fsprogs) -* Fix static build on CentOS 6 -* Possibility of using JsonCpp 0.10.6 if the compiler does not support C++11 - with the "-DUSE_LEGACY_JSONCPP=ON" CMake option -* Upgraded dependencies for static and Windows builds: - - boost 1.66.0 - - curl 7.57.0 - - jsoncpp 1.8.4 - - zlib 1.2.11 - - -Version 1.3.1 (2017-11-29) -========================== - -General -------- - -* Built-in decoding of palette images - -REST API --------- - -* New URI: "/instances/.../frames/.../raw.gz" to compress raw frames using gzip -* New argument "ignore-length" to force the inclusion of too long tags in JSON -* New argument "/.../media?extended" to include additional type-3 tags in DICOMDIR - -Plugins -------- - -* New pixel formats exposed in SDK: BGRA32, Float32, Grayscale32, RGB48 - -Maintenance ------------ - -* Creation of ./Resources/CMake/OrthancFramework*.cmake to reuse the Orthanc - C++ framework in other projects -* New security-related options: "DicomAlwaysAllowEcho" -* Use "GBK" (frequently used in China) as an alias for "GB18030" -* Experimental support of actively maintained Civetweb to replace Mongoose 3.8 -* Fix issue 31 for good (create new modality types for Philips ADW, GE Xeleris, GE AWServer) -* Fix issue 64 (OpenBSD support) -* Fix static compilation of DCMTK 3.6.2 on Fedora -* Upgrade to Boost 1.65.1 in static builds -* Upgrade to SQLite amalgamation 3.21.0 in static builds - - -Version 1.3.0 (2017-07-19) -========================== - -General -------- - -* Orthanc now anonymizes according to Basic Profile of PS 3.15-2017c Table E.1-1 -* In the "DicomModalities" configuration: - - Manufacturer type MedInria is now obsolete - - Manufacturer types AgfaImpax and SyngoVia are obsolete too - (use GenericNoWildcardInDates instead) - - Obsolete manufacturers are still accepted but might disappear in the future - - Added new manufacturer: GenericNoUniversalWildcard to replace all '*' by '' in - outgoing C-Find requests -* New security-related options: "DicomAlwaysAllowStore" and "DicomCheckModalityHost" - -REST API --------- - -* Argument "Since" in URI "/tools/find" (related to issue 53) -* Argument "DicomVersion" in URIs "/{...}/{...}/anonymization" - -Plugins -------- - -* New function: "OrthancPluginRegisterIncomingHttpRequestFilter2()" - -Lua ---- - -* Added HTTP headers support for Lua HttpPost/HttpGet/HttpPut/HttpDelete - -Orthanc Explorer ----------------- - -* Query/retrieve: Added button for "DR" modality - -Maintenance ------------ - -* Ability to retrieve raw frames encoded as unsigned 32-bits integers -* Fix issue 29 (more consistent handling of the "--upgrade" argument) -* Fix issue 31 (create new modality types for Philips ADW, GE Xeleris, GE AWServer) -* Fix issue 35 (AET name is not transferred to Orthanc using DCMTK 3.6.0) -* Fix issue 44 (bad interpretation of photometric interpretation MONOCHROME1) -* Fix issue 45 (crash when providing a folder to "--config" command-line option) -* Fix issue 46 (PHI remaining after anonymization) -* Fix issue 49 (worklists: accentuated characters are removed from C-Find responses) -* Fix issue 52 (DICOM level security association problems) -* Fix issue 55 (modification/anonymization of tags that might break the database - model now requires the "Force" parameter to be set to "true" in the query) -* Fix issue 56 (case-insensitive matching over accents) -* Fix Debian #865606 (orthanc FTBFS with libdcmtk-dev 3.6.1~20170228-2) -* Fix XSS inside DICOM in Orthanc Explorer (as reported by Victor Pasnkel, Morphus Labs) -* Upgrade to DCMTK 3.6.2 in static builds (released on 2017-07-17) -* Upgrade to Boost 1.64.0 in static builds -* New advanced "Locale" configuration option -* Removed configuration option "USE_DCMTK_361_PRIVATE_DIC" - - -Version 1.2.0 (2016/12/13) -========================== - -General -------- - -* Handling of private tags/creators in the "Dictionary" configuration option -* New configuration options: "LoadPrivateDictionary", "DicomScuTimeout" and "DicomScpTimeout" -* New metadata automatically computed at the instance level: "TransferSyntax" and "SopClassUid" - -REST API --------- - -* "/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files - (useful if private tags are registered, or if changing the default encoding) -* "Permissive" flag for URI "/modalities/{...}/store" to ignore C-STORE transfer errors -* "Asynchronous" flag for URIs "/modalities/{...}/store" and "/peers/{...}/store" - to avoid waiting for the completion of image transfers -* Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries - (useful if "Dictionary" has changed) -* "Keep" option for modifications to keep original DICOM identifiers (advanced feature) -* "/tools/default-encoding" to get or temporarily change the default encoding -* "/{resource}/{id}/reconstruct" to reconstruct the main DICOM tags, the JSON summary and - the metadata of a resource (useful to compute new metadata, or if using "Keep" above) - -Plugins -------- - -* New function: "OrthancPluginRegisterPrivateDictionaryTag()" to register private tags -* More control over client cache in the ServeFolders plugin -* New C++ help wrappers in "Plugins/Samples/Common/" to read DICOM datasets from REST API -* New data structure: "OrthancPluginFindMatcher" to match DICOM against C-FIND queries - -Maintenance ------------ - -* Fix handling of encodings in C-FIND requests (including for worklists) -* Use of DCMTK 3.6.1 dictionary of private tags in standalone builds -* Avoid hard crash if not enough memory (handling of std::bad_alloc) -* Improved robustness of Orthanc Explorer wrt. query/retrieve (maybe fix issue 24) -* Fix serious performance issue with C-FIND -* Fix extraction of the symbolic name of the private tags -* Performance warning if runtime debug assertions are turned on -* Improved robustness against files with no PatientID -* Upgrade to curl 7.50.3 for static and Windows builds -* Content-Type for JSON documents is now "application/json; charset=utf-8" -* Ignore "Group Length" tags in C-FIND queries -* Fix handling of worklist SCP with ReferencedStudySequence and ReferencedPatientSequence -* Fix handling of Move Originator AET and ID in C-MOVE SCP -* Fix vulnerability ZSL-2016-5379 "Unquoted Service Path Privilege Escalation" in the - Windows service -* Fix vulnerability ZSL-2016-5380 "Remote Memory Corruption Vulnerability" in DCMTK 3.6.0 - - -Version 1.1.0 (2016/06/27) -========================== - -General -------- - -* HTTPS client certificates can be associated with Orthanc peers to enhance security over Internet -* Possibility to use PKCS#11 authentication for hardware security modules with Orthanc peers -* New command-line option "--logfile" to output the Orthanc log to the given file -* Support of SIGHUP signal (restart Orthanc only if the configuration files have changed) - -REST API --------- - -* New URI: "/instances/.../frames/.../raw" to access the raw frames (bypass image decoding) -* New URI "/modalities/.../move" to issue C-MOVE SCU requests -* "MoveOriginatorID" can be specified for "/modalities/.../store" - -Dicom protocol --------------- - -* Support of optional tags for counting resources in C-FIND: - 0008-0061, 0008-0062, 0020-1200, 0020-1202, 0020-1204, 0020-1206, 0020-1208, 0020-1209 -* Support of Move Originator Message ID (0000,1031) in C-STORE responses driven by C-MOVE - -Plugins -------- - -* Speedup in plugins by removing unnecessary locks -* New callback to filter incoming HTTP requests: OrthancPluginRegisterIncomingHttpRequestFilter() -* New callback to handle non-worklists C-FIND requests: OrthancPluginRegisterFindCallback() -* New callback to handle C-MOVE requests: OrthancPluginRegisterMoveCallback() -* New function: "OrthancPluginHttpClient()" to do HTTP requests with full control -* New function: "OrthancPluginGenerateUuid()" to generate a UUID -* More than one custom image decoder can be installed (e.g. to handle different transfer syntaxes) - -Lua ---- - -* Possibility to dynamically fix outgoing C-FIND requests using "OutgoingFindRequestFilter()" -* Access to the HTTP headers in the "IncomingHttpRequestFilter()" callback - -Image decoding --------------- - -* Huge speedup if decoding the family of JPEG transfer syntaxes -* Refactoring leading to speedups with custom image decoders (including Web viewer plugin) -* Support decoding of RLE Lossless transfer syntax -* Support of signed 16bpp images in ParsedDicomFile - -Maintenance ------------ - -* New logo of Orthanc -* Fix issue 11 (is_regular_file() fails for FILE_ATTRIBUTE_REPARSE_POINT) -* Fix issue 16 ("Limit" parameter error in REST API /tools/find method) -* Fix of Debian bug #818512 ("FTBFS: Please install libdcmtk*-dev") -* Fix of Debian bug #823139 ("orthanc: Please provide RecoverCompressedFile.cpp") -* Replaced "localhost" by "127.0.0.1", as it might impact performance on Windows -* Compatibility with CMake >= 3.5.0 -* Possibility to use forthcoming DCMTK 3.6.1 in static builds (instead of 3.6.0) -* Upgrade to Boost 1.60.0 for static builds -* Use of HTTP status 403 Forbidden (instead of 401) if access to a REST resource is disallowed -* Option "HttpsVerifyPeers" can be used to connect against self-signed HTTPS certificates -* New configuration option "AllowFindSopClassesInStudy" -* Macro "__linux" (now obsolete) replaced by macro "__linux__" (maybe solves Debian bug #821011) -* Modification of instances can now replace PixelData (resp. EncapsulatedDocument) with - provided a PNG/JPEG image (resp. PDF file) if it is encoded using Data URI Scheme -* Dropped support of Google Log - - -Version 1.0.0 (2015/12/15) -========================== - -* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-FIND requests -* New function in plugin SDK: "OrthancPluginSendMultipartItem2()" -* Fix of DICOMDIR generation with DCMTK 3.6.1, support of encodings -* Fix range search if the lower or upper limit is absent -* Fix modality worklists lookups if tags with UN (unknown) VR are present -* Warn about badly formatted modality/peer definitions in configuration file at startup - - -Version 0.9.6 (2015/12/08) -========================== - -* Promiscuous mode (accept unknown SOP class UID) is now turned off by default -* Fix serialization of DICOM buffers that might contain garbage trailing -* Fix modality worklists server if some fields are null -* More tolerant "/series/.../ordered-slices" with broken series -* Improved logging information if upgrade fails -* Fix formatting of multipart HTTP answers (bis) - - -Version 0.9.5 (2015/12/02) -========================== - -Major ------ - -* Experimental support of DICOM C-FIND SCP for modality worklists through plugins -* Support of DICOM C-FIND SCU for modality worklists ("/modalities/{dicom}/find-worklist") - -REST API --------- - -* New URIs: - - "/series/.../ordered-slices" to order the slices of a 2D+t or 3D series - - "/tools/shutdown" to stop Orthanc from the REST API - - ".../compress", ".../uncompress" and ".../is-compressed" for attachments - - "/tools/create-archive" to create ZIP from a set of resources - - "/tools/create-media" to create ZIP+DICOMDIR from a set of resources - - "/instances/.../header" to get the meta information (header) of the DICOM instance -* "/tools/create-dicom": - - Support of binary tags encoded using data URI scheme - - Support of hierarchical structures (creation of sequences) - - Create tags with unknown VR -* "/modify" can insert/modify sequences -* ".../preview" and ".../image-uint8" can return JPEG images if the HTTP Accept Header asks so -* "Origin" metadata for the instances - -Minor ------ - -* New configuration options: - - "UnknownSopClassAccepted" to disable promiscuous mode (accept unknown SOP class UID) - - New configuration option: "Dictionary" to declare custom DICOM tags -* Add ".dcm" suffix to files in ZIP archives (cf. URI ".../archive") -* MIME content type can be associated to custom attachments (cf. "UserContentType") - -Plugins -------- - -* New functions: - - "OrthancPluginRegisterDecodeImageCallback()" to replace the built-in image decoder - - "OrthancPluginDicomInstanceToJson()" to convert DICOM to JSON - - "OrthancPluginDicomBufferToJson()" to convert DICOM to JSON - - "OrthancPluginRegisterErrorCode()" to declare custom error codes - - "OrthancPluginRegisterDictionaryTag()" to declare custom DICOM tags - - "OrthancPluginLookupDictionary()" to get information about some DICOM tag - - "OrthancPluginRestApiGet2()" to provide HTTP headers when calling Orthanc API - - "OrthancPluginGetInstanceOrigin()" to know through which mechanism an instance was received - - "OrthancPluginCreateImage()" and "OrthancPluginCreateImageAccessor()" to create images - - "OrthancPluginDecodeDicomImage()" to decode DICOM images - - "OrthancPluginComputeMd5()" and "OrthancPluginComputeSha1()" to compute MD5/SHA-1 hash -* New events in change callbacks: - - "OrthancStarted" - - "OrthancStopped" - - "UpdatedAttachment" - - "UpdatedMetadata" -* "/system" URI gives information about the plugins used for storage area and DB back-end -* Plugin callbacks must now return explicit "OrthancPluginErrorCode" (instead of integers) - -Lua ---- - -* Optional argument "keepStrings" in "DumpJson()" - -Maintenance ------------ - -* Full indexation of the patient/study tags to speed up searches and C-FIND -* Many refactorings, notably of the searching features and of the image decoding -* C-MOVE SCP for studies using AccessionNumber tag -* Fix issue 4 (C-STORE Association not renegotiated on Specific-to-specific transfer syntax change) -* Fix formatting of multipart HTTP answers -* "--logdir" flag creates a single log file instead of 3 separate files for errors/warnings/infos -* "--errors" flag lists the error codes that could be returned by Orthanc -* Under Windows, the exit status of Orthanc corresponds to the encountered error code -* New "AgfaImpax", "EFilm2" and "Vitrea" modality manufacturers -* C-FIND SCP will return tags with sequence value representation -* Upgrade to Boost 1.59.0 for static builds - - -Version 0.9.4 (2015/09/16) -========================== - -* Preview of PDF files encapsulated in DICOM from Orthanc Explorer -* Creation of DICOM files with encapsulated PDF through "/tools/create-dicom" -* "limit" and "since" arguments while retrieving DICOM resources in the REST API -* Support of "deflate" and "gzip" content-types in HTTP requests -* Options to validate peers against CA certificates in HTTPS requests -* New configuration option: "HttpTimeout" to set the default timeout for HTTP requests - -Lua ---- - -* More information about the origin request in the "OnStoredInstance()" and - "ReceivedInstanceFilter()" callbacks. WARNING: This can result in - incompatibilities wrt. previous versions of Orthanc. -* New function "GetOrthancConfiguration()" to get the Orthanc configuration - -Plugins -------- - -* New functions to compress/uncompress images using PNG and JPEG -* New functions to issue HTTP requests from plugins -* New function "OrthancPluginBufferCompression()" to (un)compress memory buffers -* New function "OrthancPluginReadFile()" to read files from the filesystem -* New function "OrthancPluginWriteFile()" to write files to the filesystem -* New function "OrthancPluginGetErrorDescription()" to convert error codes to strings -* New function "OrthancPluginSendHttpStatus()" to send HTTP status with a body -* New function "OrthancPluginRegisterRestCallbackNoLock()" for high-performance plugins -* Plugins have access to explicit error codes -* Improvements to the sample "ServeFolders" plugin -* Primitives to upgrade the database version in plugins - -Maintenance ------------ - -* Many code refactorings -* Improved error codes (no more custom descriptions in exceptions) -* If error while calling the REST API, the answer body contains description of the error - (this feature can be disabled with the "HttpDescribeErrors" option) -* Upgrade to curl 7.44.0 for static and Windows builds -* Upgrade to openssl 1.0.2d for static and Windows builds -* Depends on libjpeg 9a -* Bypass zlib uncompression if "StorageCompression" is enabled and HTTP client supports deflate - - -Version 0.9.3 (2015/08/07) -========================== - -* C-Echo testing can be triggered from Orthanc Explorer (in the query/retrieve page) -* Removal of the dependency upon Google Log, Orthanc now uses its internal logger - (use -DENABLE_GOOGLE_LOG=ON to re-enable Google Log) -* Upgrade to JsonCpp 0.10.5 for static and Windows builds - - -Version 0.9.2 (2015/08/02) -========================== - -* Upgrade to Boost 1.58.0 for static and Windows builds -* Source code repository moved from Google Code to BitBucket -* Inject version information into Windows binaries -* Fix access to binary data in HTTP/REST requests by Lua scripts -* Fix potential deadlock in the callbacks of plugins - - -Version 0.9.1 (2015/07/02) -========================== - -General -------- - -* The configuration can be splitted into several files stored inside the same folder -* Custom setting of the local AET during C-STORE SCU (both in Lua and in the REST API) -* Many code refactorings - -Lua ---- - -* Access to the REST API of Orthanc (RestApiGet, RestApiPost, RestApiPut, RestApiDelete) -* Functions to convert between Lua values and JSON strings: "ParseJson" and "DumpJson" -* New events: "OnStablePatient", "OnStableStudy", "OnStableSeries", "Initialize", "Finalize" - -Plugins -------- - -* Plugins can retrieve the configuration file directly as a JSON string -* Plugins can send answers as multipart messages - -Fixes ------ - -* Fix compatibility issues for C-FIND SCU to Siemens Syngo.Via modalities SCP -* Fix issue 15 (Lua scripts making HTTP requests) -* Fix issue 35 (Characters in PatientID string are not protected for C-FIND) -* Fix issue 37 (Hyphens trigger range query even if datatype does not support ranges) - - -Version 0.9.0 (2015/06/03) -========================== - -Major ------ - -* DICOM Query/Retrieve available from Orthanc Explorer -* C-MOVE SCU and C-FIND SCU are accessible through the REST API -* "?expand" flag for URIs "/patients", "/studies" and "/series" -* "/tools/find" URI to search for DICOM resources from REST -* Support of FreeBSD -* The "Orthanc Client" SDK is now a separate project - -Minor ------ - -* Speed-up in Orthanc Explorer for large amount of images -* Speed-up of the C-FIND SCP server of Orthanc -* Allow replacing PatientID/StudyInstanceUID/SeriesInstanceUID from Lua scripts -* Option "CaseSensitivePN" to enable case-insensitive C-FIND SCP - -Fixes ------ - -* Prevent freeze on C-FIND if no DICOM tag is to be returned -* Fix slow C-STORE SCP on recent versions of GNU/Linux, if - USE_SYSTEM_DCMTK is set to OFF (http://forum.dcmtk.org/viewtopic.php?f=1&t=4009) -* Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052)) -* Fix issue 32 (Cyrillic symbols): Introduction of the "Windows1251" encoding -* Plugins now receive duplicated GET arguments in their REST callbacks - - -Version 0.8.6 (2015/02/12) -========================== - -Major ------ - -* URIs to get all the parents of a given resource in a single REST call -* Instances without PatientID are now allowed -* Support of HTTP proxy to access Orthanc peers - -Minor ------ - -* Support of Tudor DICOM in Query/Retrieve -* More flexible "/modify" and "/anonymize" for single instance -* Access to called AET and remote AET from Lua scripts ("OnStoredInstance") -* Option "DicomAssociationCloseDelay" to set delay before closing DICOM association -* ZIP archives now display the accession number of the studies - -Plugins -------- - -* Introspection of plugins (cf. the "/plugins" URI) -* Plugins can access the command-line arguments used to launch Orthanc -* Plugins can extend Orthanc Explorer with custom JavaScript -* Plugins can get/set global properties to save their configuration -* Plugins can do REST calls to other plugins (cf. "xxxAfterPlugins()") -* Scan of folders for plugins - -Fixes ------ - -* Code refactorings -* Fix issue 25 (AET with underscore not allowed) -* Fix replacement and insertion of private DICOM tags -* Fix anonymization generating non-portable DICOM files - - -Version 0.8.5 (2014/11/04) -========================== - -General -------- - -* Major speed-up thanks to a new database schema -* Plugins can monitor changes through callbacks -* Download ZIP + DICOMDIR from Orthanc Explorer -* Sample plugin framework to serve static resources (./Plugins/Samples/WebSkeleton/) - -Fixes ------ - -* Fix issue 19 (YBR_FULL are decoded incorrectly) -* Fix issue 21 (Microsoft Visual Studio precompiled headers) -* Fix issue 22 (Error decoding multi-frame instances) -* Fix issue 24 (Build fails on OSX when directory has .DS_Store files) -* Fix crash when bad HTTP credentials are provided - - -Version 0.8.4 (2014/09/19) -========================== - -* "/instances-tags" to get the tags of all the child instances of a - patient/study/series with a single REST call (bulk tags retrieval) -* Configuration/Lua to select the accepted C-STORE SCP transfer syntaxes -* Fix reporting of errors in Orthanc Explorer when sending images to peers/modalities -* Installation of plugin SDK in CMake - - -Version 0.8.3 (2014/09/11) -========================== - -Major ------ - -* Creation of ZIP archives for media storage, with DICOMDIR -* URIs to get all the children of a given resource in a single REST call -* "/tools/lookup" URI to map DICOM UIDs to Orthanc identifiers -* Support of index-only mode (using the "StoreDicom" option) -* Plugins can implement a custom storage area - -Minor ------ - -* Configuration option to enable HTTP Keep-Alive -* Configuration option to disable the logging of exported resources in "/exports" -* Plugins can retrieve the path to Orthanc and to its configuration file -* "/tools/create-dicom" now accepts the "PatientID" DICOM tag (+ updated sample) -* Possibility to set HTTP headers from plugins -* "LastUpdate" metadata is now always returned for patients, studies and series - -Maintenance ------------ - -* Refactoring of HttpOutput ("Content-Length" header is now always sent) -* Upgrade to Mongoose 3.8 -* Fixes for Visual Studio 2013 and Windows 64bit -* Fix issue 16: Handling of "AT" value representations in JSON -* Fix issue 17 - - -Version 0.8.2 (2014/08/07) -========================== - -* Support of the standard text encodings -* Hot restart of Orthanc by posting to "/tools/reset" -* More fault-tolerant commands in Lua scripts -* Parameter to set the default encoding for DICOM files without SpecificCharacterSet -* Fix of issue #14 (support of XCode 5.1) -* Upgrade to Google Test 1.7.0 - - -Version 0.8.1 (2014/07/29) -========================== - -General -------- - -* Access patient module at the study level to cope with PatientID collisions -* On-the-fly conversion of JSON to XML according to the HTTP Accept header -* C-Echo SCU in the REST API -* DICOM conformance statement available at URI "/tools/dicom-conformance" - -Lua scripts ------------ - -* Lua scripts can do HTTP requests, and thus can call Web services -* Lua scripts can invoke system commands, with CallSystem() - -Plugins -------- - -* Lookup for DICOM UIDs in the plugin SDK -* Plugins have access to the HTTP headers and can answer with HTTP status codes -* Callback to react to the incoming of DICOM instances - -Fixes ------ - -* Fix build of Google Log with Visual Studio >= 11.0 -* Fix automated generation of the list of resource children in the REST API - - -Version 0.8.0 (2014/07/10) -========================== - -Major changes -------------- - -* Routing images with Lua scripts -* Introduction of the Orthanc Plugin SDK -* Official support of OS X (Darwin) 10.8 - -Minor changes -------------- - -* Extraction of tags for the patient/study/series/instance DICOM modules -* Extraction of the tags shared by all the instances of a patient/study/series -* Options to limit the number of results for an incoming C-FIND query -* Support of kFreeBSD -* Several code refactorings -* Fix OrthancCppClient::GetVoxelSizeZ() - - -Version 0.7.6 (2014/06/11) -========================== - -* Support of JPEG and JPEG-LS decompression -* Download DICOM images as Matlab/Octave arrays -* Precompiled headers for Microsoft Visual Studio - - -Version 0.7.5 (2014/05/08) -========================== - -* Dynamic negotiation of SOP classes for C-STORE SCU -* Creation of DICOM instances using the REST API -* Embedding of images within DICOM instances -* Adding/removal/modification of remote modalities/peers through REST -* Reuse of the previous SCU connection to avoid unnecessary handshakes -* Fix problems with anonymization and modification -* Fix missing licensing terms about reuse of some code from DCMTK -* Various code refactorings - - -Version 0.7.4 (2014/04/16) -========================== - -* Switch to openssl-1.0.1g in static builds (cf. Heartbleed exploit) -* Switch to boost 1.55.0 in static builds (to solve compiling errors) -* Better logging about nonexistent tags -* Dcm4Chee manufacturer -* Automatic discovering of the path to the DICOM dictionaries -* In the "DicomModalities" config, the port number can be a string - - -Version 0.7.3 (2014/02/14) -========================== - -Major changes -------------- - -* Fixes in the implementation of the C-FIND handler for Query/Retrieve -* Custom attachment of files to patients, studies, series or instances -* Access to lowlevel info about the attached files through the REST API -* Recover pixel data for more transfer syntaxes (notably JPEG) - -Minor changes -------------- - -* AET comparison is now case-insensitive by default -* Possibility to disable the HTTP server or the DICOM server -* Automatic computation of MD5 hashes for the stored DICOM files -* Maintenance tool to recover DICOM files compressed by Orthanc -* The newline characters in the configuration file are fixed for GNU/Linux -* Capture of the SIGTERM signal in GNU/Linux - - -Version 0.7.2 (2013/11/08) -========================== - -* Support of Query/Retrieve from medInria -* Accept more transfer syntaxes for C-STORE SCP and SCU (notably JPEG) -* Create the meta-header when receiving files through C-STORE SCP -* Fixes and improvements thanks to the static analyzer cppcheck - - -Version 0.7.1 (2013/10/30) -========================== - -* Use ZIP64 only when required to improve compatibility (cf. issue #7) -* Refactoring of the CMake options -* Fix for big-endian architectures (RedHat bug #985748) -* Use filenames with 8 characters in ZIP files for maximum compatibility -* Possibility to build Orthanc inplace (in the source directory) - - -Version 0.7.0 (2013/10/25) -========================== - -Major changes -------------- - -* DICOM Query/Retrieve is supported - -Minor changes -------------- - -* Possibility to keep the PatientID during an anonymization -* Check whether "unzip", "tar" and/or "7-zip" are installed from CMake - - -Version 0.6.2 (2013/10/04) -========================== - -* Build of the C++ client as a shared library -* Improvements and documentation of the C++ client API -* Fix of Debian bug #724947 (licensing issue with the SHA-1 library) -* Switch to Boost 1.54.0 (cf. issue #9) -* "make uninstall" is now possible - - -Version 0.6.1 (2013/09/16) -========================== - -* Detection of stable patients/studies/series -* C-FIND SCU at the instance level -* Link from modified to original resource in Orthanc Explorer -* Fix of issue #8 -* Anonymization of the medical alerts tag (0010,2000) - - -Version 0.6.0 (2013/07/16) -========================== - -Major changes -------------- - -* Introduction of the C++ client -* Send DICOM resources to other Orthanc instances through HTTP -* Access to signed images (instances/.../image-int16) - (Closes: Debian #716958) - -Minor changes -------------- - -* Export of DICOM files to the host filesystem (instances/.../export) -* Statistics about patients, studies, series and instances -* Link from anonymized to original resource in Orthanc Explorer -* Fixes for Red Hat and Debian packaging -* Fixes for history in Orthanc Explorer -* Fixes for boost::thread, as reported by Cyril Paulus -* Fix licensing (Closes: Debian #712038) - -Metadata --------- - -* Access to the metadata through the REST API (.../metadata) -* Support of user-defined metadata -* "LastUpdate" metadata for patients, studies and series -* "/tools/now" to be used in combination with "LastUpdate" -* Improved support of series with temporal positions - - -Version 0.5.2 (2013/05/07) -========================== - -* "Bulk" Store-SCU (send several DICOM instances with the same - DICOM connection) -* Store-SCU for patients and studies in Orthanc Explorer -* Filtering of incoming DICOM instances (through Lua scripting) -* Filtering of incoming HTTP requests (through Lua scripting) -* Clearing of "/exports" and "/changes" -* Check MD5 of third party downloads -* Faking of the HTTP methods PUT and DELETE - - -Version 0.5.1 (2013/04/17) -========================== - -* Support of RGB images -* Fix of store SCU in release builds -* Possibility to store the SQLite index at another place than the - DICOM instances (for performance) - - -Version 0.5.0 (2013/01/31) -========================== - -Major changes -------------- - -* Download of modified or anonymized DICOM instances -* Inplace modification and anonymization of DICOM series, studies and patients - -Minor changes -------------- - -* Support of private tags -* Implementation of the PMSCT_RLE1 image decoding for Philips modalities -* Generation of random DICOM UID through the REST API (/tools/generate-uid) - - -Version 0.4.0 (2012/12/14) -========================== - -Major changes -------------- - -* Recycling of disk space -* Raw access to the value of the DICOM tags in the REST API - -Minor changes -------------- - -* Protection of patients against recycling (also in Orthanc Explorer) -* The DICOM dictionaries are embedded in Windows builds - - -Version 0.3.1 (2012/12/05) -========================== - -* Download archives of patients, studies and series as ZIP files -* Orthanc now checks the version of its database schema before starting - - -Version 0.3.0 (2012/11/30) -========================== - -Major changes -------------- - -* Transparent compression of the DICOM instances on the disk -* The patient/study/series/instances are now indexed by SHA-1 digests - of their DICOM Instance IDs (and not by UUIDs anymore): The same - DICOM objects are thus always identified by the same Orthanc IDs -* Log of exported instances through DICOM C-STORE SCU ("/exported" URI) -* Full refactoring of the DB schema and of the REST API -* Introduction of generic classes for REST APIs (in Core/RestApi) - -Minor changes -------------- - -* "/statistics" URI -* "last" flag to retrieve the last change from the "/changes" URI -* Generate a sample configuration file from command line -* "CompletedSeries" event in the changes API -* Thread to continuously flush DB to disk (SQLite checkpoints for - improved robustness) - - -Version 0.2.3 (2012/10/26) -========================== - -* Use HTTP Content-Disposition to set a filename when downloading JSON/DCM -* URI "/system" for general information about Orthanc -* Versioning info and help on the command line -* Improved logging -* Possibility of dynamic linking against jsoncpp, sqlite, boost and dmctk - for Debian packaging -* Fix some bugs -* Switch to default 8042 port for HTTP - - -Version 0.2.2 (2012/10/04) -========================== - -* Switch to Google Log -* Fixes to Debian packaging - - -Version 0.2.1 (2012/09/28) -========================== - -* Status of series -* Continuous Integration Server is up and running -* Ready for Debian packaging - - -Version 0.2.0 (2012/09/16) -========================== - -Major changes -------------- - -* Renaming to "Orthanc" -* Focus on security: Support of SSL, HTTP Basic Authentication and - interdiction of remote access -* Access to multi-frame images (for nuclear medicine) -* Access to the raw PNG images (in 8bpp and 16bpp) - -Minor changes -------------- - -* Change of the licensing of the "Core/SQLite" folder to BSD (to - reflect the original licensing terms of Chromium, from which the - code derives) -* Standalone build for cross-compilation - - -Version 0.1.1 (2012/07/20) -========================== - -* Fix Windows version -* Native Windows build with Microsoft Visual Studio 2005 -* Add path to storage in Configuration.json - - -Version 0.1.0 (2012/07/19) -========================== - -* Initial release diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,420 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "DatabaseLookup.h" - -#include "../../../Core/OrthancException.h" -#include "../../Search/DicomTagConstraint.h" -#include "../../ServerToolbox.h" -#include "SetOfResources.h" - -namespace Orthanc -{ - namespace Compatibility - { - namespace - { - // Anonymous namespace to avoid clashes between compiler modules - class MainTagsConstraints : boost::noncopyable - { - private: - std::vector constraints_; - - public: - ~MainTagsConstraints() - { - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - delete constraints_[i]; - } - } - - void Reserve(size_t n) - { - constraints_.reserve(n); - } - - size_t GetSize() const - { - return constraints_.size(); - } - - DicomTagConstraint& GetConstraint(size_t i) const - { - if (i >= constraints_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - assert(constraints_[i] != NULL); - return *constraints_[i]; - } - } - - void Add(const DatabaseConstraint& constraint) - { - constraints_.push_back(new DicomTagConstraint(constraint)); - } - }; - } - - - static void ApplyIdentifierConstraint(SetOfResources& candidates, - ILookupResources& compatibility, - const DatabaseConstraint& constraint, - ResourceType level) - { - std::list matches; - - switch (constraint.GetConstraintType()) - { - case ConstraintType_Equal: - compatibility.LookupIdentifier(matches, level, constraint.GetTag(), - IdentifierConstraintType_Equal, constraint.GetSingleValue()); - break; - - case ConstraintType_SmallerOrEqual: - compatibility.LookupIdentifier(matches, level, constraint.GetTag(), - IdentifierConstraintType_SmallerOrEqual, constraint.GetSingleValue()); - break; - - case ConstraintType_GreaterOrEqual: - compatibility.LookupIdentifier(matches, level, constraint.GetTag(), - IdentifierConstraintType_GreaterOrEqual, constraint.GetSingleValue()); - - break; - - case ConstraintType_Wildcard: - compatibility.LookupIdentifier(matches, level, constraint.GetTag(), - IdentifierConstraintType_Wildcard, constraint.GetSingleValue()); - - break; - - case ConstraintType_List: - for (size_t i = 0; i < constraint.GetValuesCount(); i++) - { - std::list tmp; - compatibility.LookupIdentifier(tmp, level, constraint.GetTag(), - IdentifierConstraintType_Wildcard, constraint.GetValue(i)); - matches.splice(matches.end(), tmp); - } - - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - candidates.Intersect(matches); - } - - - static void ApplyIdentifierRange(SetOfResources& candidates, - ILookupResources& compatibility, - const DatabaseConstraint& smaller, - const DatabaseConstraint& greater, - ResourceType level) - { - assert(smaller.GetConstraintType() == ConstraintType_SmallerOrEqual && - greater.GetConstraintType() == ConstraintType_GreaterOrEqual && - smaller.GetTag() == greater.GetTag() && - ServerToolbox::IsIdentifier(smaller.GetTag(), level)); - - std::list matches; - compatibility.LookupIdentifierRange(matches, level, smaller.GetTag(), - greater.GetSingleValue(), smaller.GetSingleValue()); - candidates.Intersect(matches); - } - - - static void ApplyLevel(SetOfResources& candidates, - IDatabaseWrapper& database, - ILookupResources& compatibility, - const std::vector& lookup, - ResourceType level) - { - typedef std::set SetOfConstraints; - typedef std::map Identifiers; - - // (1) Select which constraints apply to this level, and split - // them between "identifier tags" constraints and "main DICOM - // tags" constraints - - Identifiers identifiers; - SetOfConstraints mainTags; - - for (size_t i = 0; i < lookup.size(); i++) - { - if (lookup[i].GetLevel() == level) - { - if (lookup[i].IsIdentifier()) - { - identifiers[lookup[i].GetTag()].insert(&lookup[i]); - } - else - { - mainTags.insert(&lookup[i]); - } - } - } - - - // (2) Apply the constraints over the identifiers - - for (Identifiers::const_iterator it = identifiers.begin(); - it != identifiers.end(); ++it) - { - // Check whether some range constraint over identifiers is - // present at this level - const DatabaseConstraint* smaller = NULL; - const DatabaseConstraint* greater = NULL; - - for (SetOfConstraints::const_iterator it2 = it->second.begin(); - it2 != it->second.end(); ++it2) - { - assert(*it2 != NULL); - - if ((*it2)->GetConstraintType() == ConstraintType_SmallerOrEqual) - { - smaller = *it2; - } - - if ((*it2)->GetConstraintType() == ConstraintType_GreaterOrEqual) - { - greater = *it2; - } - } - - if (smaller != NULL && - greater != NULL) - { - // There is a range constraint: Apply it, as it is more efficient - ApplyIdentifierRange(candidates, compatibility, *smaller, *greater, level); - } - else - { - smaller = NULL; - greater = NULL; - } - - for (SetOfConstraints::const_iterator it2 = it->second.begin(); - it2 != it->second.end(); ++it2) - { - // Check to avoid applying twice the range constraint - if (*it2 != smaller && - *it2 != greater) - { - ApplyIdentifierConstraint(candidates, compatibility, **it2, level); - } - } - } - - - // (3) Apply the constraints over the main DICOM tags (no index - // here, so this is less efficient than filtering over the - // identifiers) - if (!mainTags.empty()) - { - MainTagsConstraints c; - c.Reserve(mainTags.size()); - - for (SetOfConstraints::const_iterator it = mainTags.begin(); - it != mainTags.end(); ++it) - { - assert(*it != NULL); - c.Add(**it); - } - - std::list source; - candidates.Flatten(compatibility, source); - candidates.Clear(); - - std::list filtered; - for (std::list::const_iterator candidate = source.begin(); - candidate != source.end(); ++candidate) - { - DicomMap tags; - database.GetMainDicomTags(tags, *candidate); - - bool match = true; - - for (size_t i = 0; i < c.GetSize(); i++) - { - if (!c.GetConstraint(i).IsMatch(tags)) - { - match = false; - break; - } - } - - if (match) - { - filtered.push_back(*candidate); - } - } - - candidates.Intersect(filtered); - } - } - - - static std::string GetOneInstance(IDatabaseWrapper& compatibility, - int64_t resource, - ResourceType level) - { - for (int i = level; i < ResourceType_Instance; i++) - { - assert(compatibility.GetResourceType(resource) == static_cast(i)); - - std::list children; - compatibility.GetChildrenInternalId(children, resource); - - if (children.empty()) - { - throw OrthancException(ErrorCode_Database); - } - - resource = children.front(); - } - - return compatibility.GetPublicId(resource); - } - - - void DatabaseLookup::ApplyLookupResources(std::list& resourcesId, - std::list* instancesId, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit) - { - // This is a re-implementation of - // "../../../Resources/Graveyard/DatabaseOptimizations/LookupResource.cpp" - - assert(ResourceType_Patient < ResourceType_Study && - ResourceType_Study < ResourceType_Series && - ResourceType_Series < ResourceType_Instance); - - ResourceType upperLevel = queryLevel; - ResourceType lowerLevel = queryLevel; - - for (size_t i = 0; i < lookup.size(); i++) - { - ResourceType level = lookup[i].GetLevel(); - - if (level < upperLevel) - { - upperLevel = level; - } - - if (level > lowerLevel) - { - lowerLevel = level; - } - } - - assert(upperLevel <= queryLevel && - queryLevel <= lowerLevel); - - SetOfResources candidates(database_, upperLevel); - - for (int level = upperLevel; level <= lowerLevel; level++) - { - ApplyLevel(candidates, database_, compatibility_, lookup, static_cast(level)); - - if (level != lowerLevel) - { - candidates.GoDown(); - } - } - - std::list resources; - candidates.Flatten(compatibility_, resources); - - // Climb up, up to queryLevel - - for (int level = lowerLevel; level > queryLevel; level--) - { - std::list parents; - for (std::list::const_iterator - it = resources.begin(); it != resources.end(); ++it) - { - int64_t parent; - if (database_.LookupParent(parent, *it)) - { - parents.push_back(parent); - } - } - - resources.swap(parents); - } - - // Apply the limit, if given - - if (limit != 0 && - resources.size() > limit) - { - resources.resize(limit); - } - - // Get the public ID of all the selected resources - - size_t pos = 0; - - for (std::list::const_iterator - it = resources.begin(); it != resources.end(); ++it, pos++) - { - assert(database_.GetResourceType(*it) == queryLevel); - - const std::string resource = database_.GetPublicId(*it); - resourcesId.push_back(resource); - - if (instancesId != NULL) - { - if (queryLevel == ResourceType_Instance) - { - // The resource is itself the instance - instancesId->push_back(resource); - } - else - { - // Collect one child instance for each of the selected resources - instancesId->push_back(GetOneInstance(database_, *it, queryLevel)); - } - } - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/DatabaseLookup.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IDatabaseWrapper.h" -#include "ILookupResources.h" - -namespace Orthanc -{ - namespace Compatibility - { - class DatabaseLookup : public boost::noncopyable - { - private: - IDatabaseWrapper& database_; - ILookupResources& compatibility_; - - public: - DatabaseLookup(IDatabaseWrapper& database, - ILookupResources& compatibility) : - database_(database), - compatibility_(compatibility) - { - } - - void ApplyLookupResources(std::list& resourcesId, - std::list* instancesId, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,157 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "ICreateInstance.h" - -#include "../../../Core/OrthancException.h" - -namespace Orthanc -{ - namespace Compatibility - { - bool ICreateInstance::Apply(ICreateInstance& database, - IDatabaseWrapper::CreateInstanceResult& result, - int64_t& instanceId, - const std::string& hashPatient, - const std::string& hashStudy, - const std::string& hashSeries, - const std::string& hashInstance) - { - { - ResourceType type; - int64_t tmp; - - if (database.LookupResource(tmp, type, hashInstance)) - { - // The instance already exists - assert(type == ResourceType_Instance); - instanceId = tmp; - return false; - } - } - - instanceId = database.CreateResource(hashInstance, ResourceType_Instance); - - result.isNewPatient_ = false; - result.isNewStudy_ = false; - result.isNewSeries_ = false; - result.patientId_ = -1; - result.studyId_ = -1; - result.seriesId_ = -1; - - // Detect up to which level the patient/study/series/instance - // hierarchy must be created - - { - ResourceType dummy; - - if (database.LookupResource(result.seriesId_, dummy, hashSeries)) - { - assert(dummy == ResourceType_Series); - // The patient, the study and the series already exist - - bool ok = (database.LookupResource(result.patientId_, dummy, hashPatient) && - database.LookupResource(result.studyId_, dummy, hashStudy)); - assert(ok); - } - else if (database.LookupResource(result.studyId_, dummy, hashStudy)) - { - assert(dummy == ResourceType_Study); - - // New series: The patient and the study already exist - result.isNewSeries_ = true; - - bool ok = database.LookupResource(result.patientId_, dummy, hashPatient); - assert(ok); - } - else if (database.LookupResource(result.patientId_, dummy, hashPatient)) - { - assert(dummy == ResourceType_Patient); - - // New study and series: The patient already exist - result.isNewStudy_ = true; - result.isNewSeries_ = true; - } - else - { - // New patient, study and series: Nothing exists - result.isNewPatient_ = true; - result.isNewStudy_ = true; - result.isNewSeries_ = true; - } - } - - // Create the series if needed - if (result.isNewSeries_) - { - result.seriesId_ = database.CreateResource(hashSeries, ResourceType_Series); - } - - // Create the study if needed - if (result.isNewStudy_) - { - result.studyId_ = database.CreateResource(hashStudy, ResourceType_Study); - } - - // Create the patient if needed - if (result.isNewPatient_) - { - result.patientId_ = database.CreateResource(hashPatient, ResourceType_Patient); - } - - // Create the parent-to-child links - database.AttachChild(result.seriesId_, instanceId); - - if (result.isNewSeries_) - { - database.AttachChild(result.studyId_, result.seriesId_); - } - - if (result.isNewStudy_) - { - database.AttachChild(result.patientId_, result.studyId_); - } - - database.TagMostRecentPatient(result.patientId_); - - // Sanity checks - assert(result.patientId_ != -1); - assert(result.studyId_ != -1); - assert(result.seriesId_ != -1); - assert(instanceId != -1); - - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ICreateInstance.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IDatabaseWrapper.h" - -namespace Orthanc -{ - namespace Compatibility - { - class ICreateInstance : public boost::noncopyable - { - public: - virtual bool LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) = 0; - - virtual int64_t CreateResource(const std::string& publicId, - ResourceType type) = 0; - - virtual void AttachChild(int64_t parent, - int64_t child) = 0; - - virtual void TagMostRecentPatient(int64_t patientId) = 0; - - static bool Apply(ICreateInstance& database, - IDatabaseWrapper::CreateInstanceResult& result, - int64_t& instanceId, - const std::string& patient, - const std::string& study, - const std::string& series, - const std::string& instance); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "IGetChildrenMetadata.h" - -namespace Orthanc -{ - namespace Compatibility - { - void IGetChildrenMetadata::Apply(IGetChildrenMetadata& database, - std::list& target, - int64_t resourceId, - MetadataType metadata) - { - // This function comes from an optimization of - // "ServerIndex::GetSeriesStatus()" in Orthanc <= 1.5.1 - // Loop over the instances of this series - - target.clear(); - - std::list children; - database.GetChildrenInternalId(children, resourceId); - - for (std::list::const_iterator - it = children.begin(); it != children.end(); ++it) - { - std::string value; - if (database.LookupMetadata(value, *it, metadata)) - { - target.push_back(value); - } - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/IGetChildrenMetadata.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../ServerEnumerations.h" - -#include -#include - -namespace Orthanc -{ - namespace Compatibility - { - class IGetChildrenMetadata : public boost::noncopyable - { - public: - virtual void GetChildrenInternalId(std::list& target, - int64_t id) = 0; - - virtual bool LookupMetadata(std::string& target, - int64_t id, - MetadataType type) = 0; - - static void Apply(IGetChildrenMetadata& database, - std::list& target, - int64_t resourceId, - MetadataType metadata); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "ILookupResourceAndParent.h" - -#include "../../../Core/OrthancException.h" - -namespace Orthanc -{ - namespace Compatibility - { - bool ILookupResourceAndParent::Apply(ILookupResourceAndParent& database, - int64_t& id, - ResourceType& type, - std::string& parentPublicId, - const std::string& publicId) - { - if (!database.LookupResource(id, type, publicId)) - { - return false; - } - else if (type == ResourceType_Patient) - { - parentPublicId.clear(); - return true; - } - else - { - int64_t parentId; - if (!database.LookupParent(parentId, id)) - { - throw OrthancException(ErrorCode_InternalError); - } - - parentPublicId = database.GetPublicId(parentId); - return true; - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResourceAndParent.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,64 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../ServerEnumerations.h" - -#include -#include - -namespace Orthanc -{ - namespace Compatibility - { - class ILookupResourceAndParent : public boost::noncopyable - { - public: - virtual bool LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) = 0; - - virtual bool LookupParent(int64_t& parentId, - int64_t resourceId) = 0; - - virtual std::string GetPublicId(int64_t resourceId) = 0; - - static bool Apply(ILookupResourceAndParent& database, - int64_t& id, - ResourceType& type, - std::string& parentPublicId, - const std::string& publicId); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "ILookupResources.h" - -#include "DatabaseLookup.h" - -namespace Orthanc -{ - namespace Compatibility - { - void ILookupResources::Apply( - IDatabaseWrapper& database, - ILookupResources& compatibility, - std::list& resourcesId, - std::list* instancesId, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit) - { - Compatibility::DatabaseLookup compat(database, compatibility); - compat.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, limit); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ILookupResources.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,78 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../IDatabaseWrapper.h" - -namespace Orthanc -{ - namespace Compatibility - { - /** - * This is a compatibility class that contains database primitives - * that were used in Orthanc <= 1.5.1, and that have been removed - * during the optimization of the database engine. - **/ - class ILookupResources : public boost::noncopyable - { - public: - virtual ~ILookupResources() - { - } - - virtual void GetAllInternalIds(std::list& target, - ResourceType resourceType) = 0; - - virtual void LookupIdentifier(std::list& result, - ResourceType level, - const DicomTag& tag, - IdentifierConstraintType type, - const std::string& value) = 0; - - virtual void LookupIdentifierRange(std::list& result, - ResourceType level, - const DicomTag& tag, - const std::string& start, - const std::string& end) = 0; - - static void Apply(IDatabaseWrapper& database, - ILookupResources& compatibility, - std::list& resourcesId, - std::list* instancesId, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit); - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ISetResourcesContent.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ISetResourcesContent.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ISetResourcesContent.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/ISetResourcesContent.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../ResourcesContent.h" - -namespace Orthanc -{ - namespace Compatibility - { - class ISetResourcesContent : public boost::noncopyable - { - public: - virtual ~ISetResourcesContent() - { - } - - virtual void SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value) = 0; - - virtual void SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value) = 0; - - virtual void SetMetadata(int64_t id, - MetadataType type, - const std::string& value) = 0; - - static void Apply(ISetResourcesContent& that, - const ResourcesContent& content) - { - content.Store(that); - } - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "SetOfResources.h" - -#include "../../../Core/OrthancException.h" - - -namespace Orthanc -{ - namespace Compatibility - { - void SetOfResources::Intersect(const std::list& resources) - { - if (resources_.get() == NULL) - { - resources_.reset(new Resources); - - for (std::list::const_iterator - it = resources.begin(); it != resources.end(); ++it) - { - resources_->insert(*it); - } - } - else - { - std::unique_ptr filtered(new Resources); - - for (std::list::const_iterator - it = resources.begin(); it != resources.end(); ++it) - { - if (resources_->find(*it) != resources_->end()) - { - filtered->insert(*it); - } - } - -#if __cplusplus < 201103L - resources_.reset(filtered.release()); -#else - resources_ = std::move(filtered); -#endif - } - } - - - void SetOfResources::GoDown() - { - if (level_ == ResourceType_Instance) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (resources_.get() != NULL) - { - std::unique_ptr children(new Resources); - - for (Resources::const_iterator it = resources_->begin(); - it != resources_->end(); ++it) - { - std::list tmp; - database_.GetChildrenInternalId(tmp, *it); - - for (std::list::const_iterator - child = tmp.begin(); child != tmp.end(); ++child) - { - children->insert(*child); - } - } - -#if __cplusplus < 201103L - resources_.reset(children.release()); -#else - resources_ = std::move(children); -#endif - } - - switch (level_) - { - case ResourceType_Patient: - level_ = ResourceType_Study; - break; - - case ResourceType_Study: - level_ = ResourceType_Series; - break; - - case ResourceType_Series: - level_ = ResourceType_Instance; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - void SetOfResources::Flatten(std::list& result) - { - result.clear(); - - if (resources_.get() == NULL) - { - // All the resources of this level are part of the filter - database_.GetAllPublicIds(result, level_); - } - else - { - for (Resources::const_iterator it = resources_->begin(); - it != resources_->end(); ++it) - { - result.push_back(database_.GetPublicId(*it)); - } - } - } - - - void SetOfResources::Flatten(ILookupResources& compatibility, - std::list& result) - { - result.clear(); - - if (resources_.get() == NULL) - { - // All the resources of this level are part of the filter - compatibility.GetAllInternalIds(result, level_); - } - else - { - for (Resources::const_iterator it = resources_->begin(); - it != resources_->end(); ++it) - { - result.push_back(*it); - } - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Compatibility/SetOfResources.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/Compatibility.h" -#include "../IDatabaseWrapper.h" -#include "ILookupResources.h" - -#include -#include - -namespace Orthanc -{ - namespace Compatibility - { - class SetOfResources : public boost::noncopyable - { - private: - typedef std::set Resources; - - IDatabaseWrapper& database_; - ResourceType level_; - std::unique_ptr resources_; - - public: - SetOfResources(IDatabaseWrapper& database, - ResourceType level) : - database_(database), - level_(level) - { - } - - ResourceType GetLevel() const - { - return level_; - } - - void Intersect(const std::list& resources); - - void GoDown(); - - void Flatten(ILookupResources& compatibility, - std::list& result); - - void Flatten(std::list& result); - - void Clear() - { - resources_.reset(NULL); - } - }; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseListener.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseListener.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseListener.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseListener.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../ServerEnumerations.h" -#include "../ServerIndexChange.h" - -#include - -namespace Orthanc -{ - class IDatabaseListener : public boost::noncopyable - { - public: - virtual ~IDatabaseListener() - { - } - - virtual void SignalRemainingAncestor(ResourceType parentType, - const std::string& publicId) = 0; - - virtual void SignalFileDeleted(const FileInfo& info) = 0; - - virtual void SignalChange(const ServerIndexChange& change) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseWrapper.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseWrapper.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseWrapper.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/IDatabaseWrapper.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,256 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomFormat/DicomMap.h" -#include "../../Core/FileStorage/FileInfo.h" -#include "../../Core/FileStorage/IStorageArea.h" -#include "../../Core/SQLite/ITransaction.h" - -#include "../ExportedResource.h" -#include "IDatabaseListener.h" - -#include -#include - -namespace Orthanc -{ - class DatabaseConstraint; - class ResourcesContent; - - - class IDatabaseWrapper : public boost::noncopyable - { - public: - class ITransaction : public boost::noncopyable - { - public: - virtual ~ITransaction() - { - } - - virtual void Begin() = 0; - - virtual void Rollback() = 0; - - virtual void Commit(int64_t fileSizeDelta) = 0; - }; - - - struct CreateInstanceResult - { - bool isNewPatient_; - bool isNewStudy_; - bool isNewSeries_; - int64_t patientId_; - int64_t studyId_; - int64_t seriesId_; - }; - - virtual ~IDatabaseWrapper() - { - } - - virtual void Open() = 0; - - virtual void Close() = 0; - - virtual void AddAttachment(int64_t id, - const FileInfo& attachment) = 0; - - virtual void ClearChanges() = 0; - - virtual void ClearExportedResources() = 0; - - virtual void DeleteAttachment(int64_t id, - FileContentType attachment) = 0; - - virtual void DeleteMetadata(int64_t id, - MetadataType type) = 0; - - virtual void DeleteResource(int64_t id) = 0; - - virtual void FlushToDisk() = 0; - - virtual bool HasFlushToDisk() const = 0; - - virtual void GetAllMetadata(std::map& target, - int64_t id) = 0; - - virtual void GetAllPublicIds(std::list& target, - ResourceType resourceType) = 0; - - virtual void GetAllPublicIds(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit) = 0; - - virtual void GetChanges(std::list& target /*out*/, - bool& done /*out*/, - int64_t since, - uint32_t maxResults) = 0; - - virtual void GetChildrenInternalId(std::list& target, - int64_t id) = 0; - - virtual void GetChildrenPublicId(std::list& target, - int64_t id) = 0; - - virtual void GetExportedResources(std::list& target /*out*/, - bool& done /*out*/, - int64_t since, - uint32_t maxResults) = 0; - - virtual void GetLastChange(std::list& target /*out*/) = 0; - - virtual void GetLastExportedResource(std::list& target /*out*/) = 0; - - virtual void GetMainDicomTags(DicomMap& map, - int64_t id) = 0; - - virtual std::string GetPublicId(int64_t resourceId) = 0; - - virtual uint64_t GetResourceCount(ResourceType resourceType) = 0; - - virtual ResourceType GetResourceType(int64_t resourceId) = 0; - - virtual uint64_t GetTotalCompressedSize() = 0; - - virtual uint64_t GetTotalUncompressedSize() = 0; - - virtual bool IsExistingResource(int64_t internalId) = 0; - - virtual bool IsProtectedPatient(int64_t internalId) = 0; - - virtual void ListAvailableAttachments(std::list& target, - int64_t id) = 0; - - virtual void LogChange(int64_t internalId, - const ServerIndexChange& change) = 0; - - virtual void LogExportedResource(const ExportedResource& resource) = 0; - - virtual bool LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType) = 0; - - virtual bool LookupGlobalProperty(std::string& target, - GlobalProperty property) = 0; - - virtual bool LookupMetadata(std::string& target, - int64_t id, - MetadataType type) = 0; - - virtual bool LookupParent(int64_t& parentId, - int64_t resourceId) = 0; - - virtual bool LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) = 0; - - virtual bool SelectPatientToRecycle(int64_t& internalId) = 0; - - virtual bool SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid) = 0; - - virtual void SetGlobalProperty(GlobalProperty property, - const std::string& value) = 0; - - virtual void ClearMainDicomTags(int64_t id) = 0; - - virtual void SetMetadata(int64_t id, - MetadataType type, - const std::string& value) = 0; - - virtual void SetProtectedPatient(int64_t internalId, - bool isProtected) = 0; - - virtual ITransaction* StartTransaction() = 0; - - virtual void SetListener(IDatabaseListener& listener) = 0; - - virtual unsigned int GetDatabaseVersion() = 0; - - virtual void Upgrade(unsigned int targetVersion, - IStorageArea& storageArea) = 0; - - - /** - * Primitives introduced in Orthanc 1.5.2 - **/ - - virtual bool IsDiskSizeAbove(uint64_t threshold) = 0; - - virtual void ApplyLookupResources(std::list& resourcesId, - std::list* instancesId, // Can be NULL if not needed - const std::vector& lookup, - ResourceType queryLevel, - size_t limit) = 0; - - // Returns "true" iff. the instance is new and has been inserted - // into the database. If "false" is returned, the content of - // "result" is undefined, but "instanceId" must be properly - // set. This method must also tag the parent patient as the most - // recent in the patient recycling order if it is not protected - // (so as to fix issue #58). - virtual bool CreateInstance(CreateInstanceResult& result, /* out */ - int64_t& instanceId, /* out */ - const std::string& patient, - const std::string& study, - const std::string& series, - const std::string& instance) = 0; - - // It is guaranteed that the resources to be modified have no main - // DICOM tags, and no DICOM identifiers associated with - // them. However, some metadata might be already existing, and - // have to be overwritten. - virtual void SetResourcesContent(const ResourcesContent& content) = 0; - - virtual void GetChildrenMetadata(std::list& target, - int64_t resourceId, - MetadataType metadata) = 0; - - virtual int64_t GetLastChangeIndex() = 0; - - - /** - * Primitives introduced in Orthanc 1.5.4 - **/ - - virtual bool LookupResourceAndParent(int64_t& id, - ResourceType& type, - std::string& parentPublicId, - const std::string& publicId) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/InstallTrackAttachmentsSize.sql orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/InstallTrackAttachmentsSize.sql --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/InstallTrackAttachmentsSize.sql 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/InstallTrackAttachmentsSize.sql 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -CREATE TABLE GlobalIntegers( - key INTEGER PRIMARY KEY, - value INTEGER); - -INSERT INTO GlobalProperties VALUES (6, 1); -- GlobalProperty_GetTotalSizeIsFast - -INSERT INTO GlobalIntegers SELECT 0, IFNULL(SUM(compressedSize), 0) FROM AttachedFiles; -INSERT INTO GlobalIntegers SELECT 1, IFNULL(SUM(uncompressedSize), 0) FROM AttachedFiles; - -CREATE TRIGGER AttachedFileIncrementSize -AFTER INSERT ON AttachedFiles -BEGIN - UPDATE GlobalIntegers SET value = value + new.compressedSize WHERE key = 0; - UPDATE GlobalIntegers SET value = value + new.uncompressedSize WHERE key = 1; -END; - -CREATE TRIGGER AttachedFileDecrementSize -AFTER DELETE ON AttachedFiles -BEGIN - UPDATE GlobalIntegers SET value = value - old.compressedSize WHERE key = 0; - UPDATE GlobalIntegers SET value = value - old.uncompressedSize WHERE key = 1; -END; diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/PrepareDatabase.sql orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/PrepareDatabase.sql --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/PrepareDatabase.sql 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/PrepareDatabase.sql 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -CREATE TABLE GlobalProperties( - property INTEGER PRIMARY KEY, - value TEXT - ); - -CREATE TABLE Resources( - internalId INTEGER PRIMARY KEY AUTOINCREMENT, - resourceType INTEGER, - publicId TEXT, - parentId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE - ); - -CREATE TABLE MainDicomTags( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - tagGroup INTEGER, - tagElement INTEGER, - value TEXT, - PRIMARY KEY(id, tagGroup, tagElement) - ); - --- The following table was added in Orthanc 0.8.5 (database v5) -CREATE TABLE DicomIdentifiers( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - tagGroup INTEGER, - tagElement INTEGER, - value TEXT, - PRIMARY KEY(id, tagGroup, tagElement) - ); - -CREATE TABLE Metadata( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - type INTEGER, - value TEXT, - PRIMARY KEY(id, type) - ); - -CREATE TABLE AttachedFiles( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - fileType INTEGER, - uuid TEXT, - compressedSize INTEGER, - uncompressedSize INTEGER, - compressionType INTEGER, - uncompressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) - compressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) - PRIMARY KEY(id, fileType) - ); - -CREATE TABLE Changes( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - changeType INTEGER, - internalId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - resourceType INTEGER, - date TEXT - ); - -CREATE TABLE ExportedResources( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - resourceType INTEGER, - publicId TEXT, - remoteModality TEXT, - patientId TEXT, - studyInstanceUid TEXT, - seriesInstanceUid TEXT, - sopInstanceUid TEXT, - date TEXT - ); - -CREATE TABLE PatientRecyclingOrder( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - patientId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE - ); - -CREATE INDEX ChildrenIndex ON Resources(parentId); -CREATE INDEX PublicIndex ON Resources(publicId); -CREATE INDEX ResourceTypeIndex ON Resources(resourceType); -CREATE INDEX PatientRecyclingIndex ON PatientRecyclingOrder(patientId); - -CREATE INDEX MainDicomTagsIndex1 ON MainDicomTags(id); --- The 2 following indexes were removed in Orthanc 0.8.5 (database v5), to speed up --- CREATE INDEX MainDicomTagsIndex2 ON MainDicomTags(tagGroup, tagElement); --- CREATE INDEX MainDicomTagsIndexValues ON MainDicomTags(value COLLATE BINARY); - --- The 3 following indexes were added in Orthanc 0.8.5 (database v5) -CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id); -CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement); -CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY); - -CREATE INDEX ChangesIndex ON Changes(internalId); - -CREATE TRIGGER AttachedFileDeleted -AFTER DELETE ON AttachedFiles -BEGIN - SELECT SignalFileDeleted(old.uuid, old.fileType, old.uncompressedSize, - old.compressionType, old.compressedSize, - -- These 2 arguments are new in Orthanc 0.7.3 (database v4) - old.uncompressedMD5, old.compressedMD5); -END; - -CREATE TRIGGER ResourceDeleted -AFTER DELETE ON Resources -BEGIN - SELECT SignalResourceDeleted(old.publicId, old.resourceType); -- New in Orthanc 0.8.5 (db v5) - SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) - FROM Resources AS parent WHERE internalId = old.parentId; -END; - --- Delete a parent resource when its unique child is deleted -CREATE TRIGGER ResourceDeletedParentCleaning -AFTER DELETE ON Resources -FOR EACH ROW WHEN (SELECT COUNT(*) FROM Resources WHERE parentId = old.parentId) = 0 -BEGIN - DELETE FROM Resources WHERE internalId = old.parentId; -END; - -CREATE TRIGGER PatientAdded -AFTER INSERT ON Resources -FOR EACH ROW WHEN new.resourceType = 1 -- "1" corresponds to "ResourceType_Patient" in C++ -BEGIN - INSERT INTO PatientRecyclingOrder VALUES (NULL, new.internalId); -END; - - --- Set the version of the database schema --- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration -INSERT INTO GlobalProperties VALUES (1, "6"); diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "ResourcesContent.h" - -#include "Compatibility/ISetResourcesContent.h" - -#include - - -namespace Orthanc -{ - void ResourcesContent::Store(Compatibility::ISetResourcesContent& compatibility) const - { - for (std::list::const_iterator - it = tags_.begin(); it != tags_.end(); ++it) - { - if (it->isIdentifier_) - { - compatibility.SetIdentifierTag(it->resourceId_, it->tag_, it->value_); - } - else - { - compatibility.SetMainDicomTag(it->resourceId_, it->tag_, it->value_); - } - } - - for (std::list::const_iterator - it = metadata_.begin(); it != metadata_.end(); ++it) - { - compatibility.SetMetadata(it->resourceId_, it->metadata_, it->value_); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/ResourcesContent.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,134 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomFormat/DicomMap.h" -#include "../ServerEnumerations.h" - -#include -#include - - -namespace Orthanc -{ - namespace Compatibility - { - class ISetResourcesContent; - } - - class ResourcesContent : public boost::noncopyable - { - public: - struct TagValue - { - int64_t resourceId_; - bool isIdentifier_; - DicomTag tag_; - std::string value_; - - TagValue(int64_t resourceId, - bool isIdentifier, - const DicomTag& tag, - const std::string& value) : - resourceId_(resourceId), - isIdentifier_(isIdentifier), - tag_(tag), - value_(value) - { - } - }; - - struct Metadata - { - int64_t resourceId_; - MetadataType metadata_; - std::string value_; - - Metadata(int64_t resourceId, - MetadataType metadata, - const std::string& value) : - resourceId_(resourceId), - metadata_(metadata), - value_(value) - { - } - }; - - typedef std::list ListTags; - typedef std::list ListMetadata; - - private: - ListTags tags_; - ListMetadata metadata_; - - public: - void AddMainDicomTag(int64_t resourceId, - const DicomTag& tag, - const std::string& value) - { - tags_.push_back(TagValue(resourceId, false, tag, value)); - } - - void AddIdentifierTag(int64_t resourceId, - const DicomTag& tag, - const std::string& value) - { - tags_.push_back(TagValue(resourceId, true, tag, value)); - } - - void AddMetadata(int64_t resourceId, - MetadataType metadata, - const std::string& value) - { - metadata_.push_back(Metadata(resourceId, metadata, value)); - } - - void AddResource(int64_t resource, - ResourceType level, - const DicomMap& dicomSummary); - - // WARNING: The database should be locked with a transaction! - void Store(Compatibility::ISetResourcesContent& target) const; - - const ListTags& GetListTags() const - { - return tags_; - } - - const ListMetadata& GetListMetadata() const - { - return metadata_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1353 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "SQLiteDatabaseWrapper.h" - -#include "../../Core/DicomFormat/DicomArray.h" -#include "../../Core/Logging.h" -#include "../../Core/SQLite/Transaction.h" -#include "../Search/ISqlLookupFormatter.h" -#include "../ServerToolbox.h" - -#include - -#include -#include - -namespace Orthanc -{ - namespace Internals - { - class SignalFileDeleted : public SQLite::IScalarFunction - { - private: - IDatabaseListener& listener_; - - public: - SignalFileDeleted(IDatabaseListener& listener) : - listener_(listener) - { - } - - virtual const char* GetName() const - { - return "SignalFileDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 7; - } - - virtual void Compute(SQLite::FunctionContext& context) - { - std::string uncompressedMD5, compressedMD5; - - if (!context.IsNullValue(5)) - { - uncompressedMD5 = context.GetStringValue(5); - } - - if (!context.IsNullValue(6)) - { - compressedMD5 = context.GetStringValue(6); - } - - FileInfo info(context.GetStringValue(0), - static_cast(context.GetIntValue(1)), - static_cast(context.GetInt64Value(2)), - uncompressedMD5, - static_cast(context.GetIntValue(3)), - static_cast(context.GetInt64Value(4)), - compressedMD5); - - listener_.SignalFileDeleted(info); - } - }; - - class SignalResourceDeleted : public SQLite::IScalarFunction - { - private: - IDatabaseListener& listener_; - - public: - SignalResourceDeleted(IDatabaseListener& listener) : - listener_(listener) - { - } - - virtual const char* GetName() const - { - return "SignalResourceDeleted"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(SQLite::FunctionContext& context) - { - ResourceType type = static_cast(context.GetIntValue(1)); - ServerIndexChange change(ChangeType_Deleted, type, context.GetStringValue(0)); - listener_.SignalChange(change); - } - }; - - class SignalRemainingAncestor : public SQLite::IScalarFunction - { - private: - bool hasRemainingAncestor_; - std::string remainingPublicId_; - ResourceType remainingType_; - - public: - SignalRemainingAncestor() : - hasRemainingAncestor_(false) - { - } - - void Reset() - { - hasRemainingAncestor_ = false; - } - - virtual const char* GetName() const - { - return "SignalRemainingAncestor"; - } - - virtual unsigned int GetCardinality() const - { - return 2; - } - - virtual void Compute(SQLite::FunctionContext& context) - { - VLOG(1) << "There exists a remaining ancestor with public ID \"" - << context.GetStringValue(0) - << "\" of type " - << context.GetIntValue(1); - - if (!hasRemainingAncestor_ || - remainingType_ >= context.GetIntValue(1)) - { - hasRemainingAncestor_ = true; - remainingPublicId_ = context.GetStringValue(0); - remainingType_ = static_cast(context.GetIntValue(1)); - } - } - - bool HasRemainingAncestor() const - { - return hasRemainingAncestor_; - } - - const std::string& GetRemainingAncestorId() const - { - assert(hasRemainingAncestor_); - return remainingPublicId_; - } - - ResourceType GetRemainingAncestorType() const - { - assert(hasRemainingAncestor_); - return remainingType_; - } - }; - } - - - void SQLiteDatabaseWrapper::GetChangesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) - { - target.clear(); - - while (target.size() < maxResults && s.Step()) - { - int64_t seq = s.ColumnInt64(0); - ChangeType changeType = static_cast(s.ColumnInt(1)); - ResourceType resourceType = static_cast(s.ColumnInt(3)); - const std::string& date = s.ColumnString(4); - - int64_t internalId = s.ColumnInt64(2); - std::string publicId = GetPublicId(internalId); - - target.push_back(ServerIndexChange(seq, changeType, resourceType, publicId, date)); - } - - done = !(target.size() == maxResults && s.Step()); - } - - - void SQLiteDatabaseWrapper::GetExportedResourcesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults) - { - target.clear(); - - while (target.size() < maxResults && s.Step()) - { - int64_t seq = s.ColumnInt64(0); - ResourceType resourceType = static_cast(s.ColumnInt(1)); - std::string publicId = s.ColumnString(2); - - ExportedResource resource(seq, - resourceType, - publicId, - s.ColumnString(3), // modality - s.ColumnString(8), // date - s.ColumnString(4), // patient ID - s.ColumnString(5), // study instance UID - s.ColumnString(6), // series instance UID - s.ColumnString(7)); // sop instance UID - - target.push_back(resource); - } - - done = !(target.size() == maxResults && s.Step()); - } - - - void SQLiteDatabaseWrapper::GetChildren(std::list& childrenPublicIds, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE parentId=?"); - s.BindInt64(0, id); - - childrenPublicIds.clear(); - while (s.Step()) - { - childrenPublicIds.push_back(s.ColumnString(0)); - } - } - - - void SQLiteDatabaseWrapper::DeleteResource(int64_t id) - { - signalRemainingAncestor_->Reset(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Resources WHERE internalId=?"); - s.BindInt64(0, id); - s.Run(); - - if (signalRemainingAncestor_->HasRemainingAncestor() && - listener_ != NULL) - { - listener_->SignalRemainingAncestor(signalRemainingAncestor_->GetRemainingAncestorType(), - signalRemainingAncestor_->GetRemainingAncestorId()); - } - } - - - bool SQLiteDatabaseWrapper::GetParentPublicId(std::string& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b " - "WHERE a.internalId = b.parentId AND b.internalId = ?"); - s.BindInt64(0, id); - - if (s.Step()) - { - target = s.ColumnString(0); - return true; - } - else - { - return false; - } - } - - - int64_t SQLiteDatabaseWrapper::GetTableRecordCount(const std::string& table) - { - /** - * "Generally one cannot use SQL parameters/placeholders for - * database identifiers (tables, columns, views, schemas, etc.) or - * database functions (e.g., CURRENT_DATE), but instead only for - * binding literal values." => To avoid any SQL injection, we - * check that the "table" parameter has only alphabetic - * characters. - * https://stackoverflow.com/a/1274764/881731 - **/ - for (size_t i = 0; i < table.size(); i++) - { - if (!isalpha(table[i])) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - // Don't use "SQLITE_FROM_HERE", otherwise "table" would be cached - SQLite::Statement s(db_, "SELECT COUNT(*) FROM " + table); - - if (s.Step()) - { - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - return c; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - SQLiteDatabaseWrapper::SQLiteDatabaseWrapper(const std::string& path) : - listener_(NULL), - signalRemainingAncestor_(NULL), - version_(0) - { - db_.Open(path); - } - - - SQLiteDatabaseWrapper::SQLiteDatabaseWrapper() : - listener_(NULL), - signalRemainingAncestor_(NULL), - version_(0) - { - db_.OpenInMemory(); - } - - - int SQLiteDatabaseWrapper::GetGlobalIntegerProperty(GlobalProperty property, - int defaultValue) - { - std::string tmp; - - if (!LookupGlobalProperty(tmp, GlobalProperty_DatabasePatchLevel)) - { - return defaultValue; - } - else - { - try - { - return boost::lexical_cast(tmp); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Global property " + boost::lexical_cast(property) + - " should be an integer, but found: " + tmp); - } - } - } - - - void SQLiteDatabaseWrapper::Open() - { - db_.Execute("PRAGMA ENCODING=\"UTF-8\";"); - - // Performance tuning of SQLite with PRAGMAs - // http://www.sqlite.org/pragma.html - db_.Execute("PRAGMA SYNCHRONOUS=NORMAL;"); - db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); - db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); - db_.Execute("PRAGMA WAL_AUTOCHECKPOINT=1000;"); - //db_.Execute("PRAGMA TEMP_STORE=memory"); - - // Make "LIKE" case-sensitive in SQLite - db_.Execute("PRAGMA case_sensitive_like = true;"); - - { - SQLite::Transaction t(db_); - t.Begin(); - - if (!db_.DoesTableExist("GlobalProperties")) - { - LOG(INFO) << "Creating the database"; - std::string query; - EmbeddedResources::GetFileResource(query, EmbeddedResources::PREPARE_DATABASE); - db_.Execute(query); - } - - // Check the version of the database - std::string tmp; - if (!LookupGlobalProperty(tmp, GlobalProperty_DatabaseSchemaVersion)) - { - tmp = "Unknown"; - } - - bool ok = false; - try - { - LOG(INFO) << "Version of the Orthanc database: " << tmp; - version_ = boost::lexical_cast(tmp); - ok = true; - } - catch (boost::bad_lexical_cast&) - { - } - - if (!ok) - { - throw OrthancException(ErrorCode_IncompatibleDatabaseVersion, - "Incompatible version of the Orthanc database: " + tmp); - } - - // New in Orthanc 1.5.1 - if (version_ == 6) - { - if (!LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast) || - tmp != "1") - { - LOG(INFO) << "Installing the SQLite triggers to track the size of the attachments"; - std::string query; - EmbeddedResources::GetFileResource(query, EmbeddedResources::INSTALL_TRACK_ATTACHMENTS_SIZE); - db_.Execute(query); - } - } - - t.Commit(); - } - - signalRemainingAncestor_ = new Internals::SignalRemainingAncestor; - db_.Register(signalRemainingAncestor_); - } - - - static void ExecuteUpgradeScript(SQLite::Connection& db, - EmbeddedResources::FileResourceId script) - { - std::string upgrade; - EmbeddedResources::GetFileResource(upgrade, script); - db.BeginTransaction(); - db.Execute(upgrade); - db.CommitTransaction(); - } - - - void SQLiteDatabaseWrapper::Upgrade(unsigned int targetVersion, - IStorageArea& storageArea) - { - if (targetVersion != 6) - { - throw OrthancException(ErrorCode_IncompatibleDatabaseVersion); - } - - // This version of Orthanc is only compatible with versions 3, 4, - // 5 and 6 of the DB schema - if (version_ != 3 && - version_ != 4 && - version_ != 5 && - version_ != 6) - { - throw OrthancException(ErrorCode_IncompatibleDatabaseVersion); - } - - if (version_ == 3) - { - LOG(WARNING) << "Upgrading database version from 3 to 4"; - ExecuteUpgradeScript(db_, EmbeddedResources::UPGRADE_DATABASE_3_TO_4); - version_ = 4; - } - - if (version_ == 4) - { - LOG(WARNING) << "Upgrading database version from 4 to 5"; - ExecuteUpgradeScript(db_, EmbeddedResources::UPGRADE_DATABASE_4_TO_5); - version_ = 5; - } - - if (version_ == 5) - { - LOG(WARNING) << "Upgrading database version from 5 to 6"; - // No change in the DB schema, the step from version 5 to 6 only - // consists in reconstructing the main DICOM tags information - // (as more tags got included). - db_.BeginTransaction(); - ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Patient); - ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Study); - ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Series); - ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Instance); - db_.Execute("UPDATE GlobalProperties SET value=\"6\" WHERE property=" + - boost::lexical_cast(GlobalProperty_DatabaseSchemaVersion) + ";"); - db_.CommitTransaction(); - version_ = 6; - } - } - - - void SQLiteDatabaseWrapper::SetListener(IDatabaseListener& listener) - { - listener_ = &listener; - db_.Register(new Internals::SignalFileDeleted(listener)); - db_.Register(new Internals::SignalResourceDeleted(listener)); - } - - - void SQLiteDatabaseWrapper::ClearTable(const std::string& tableName) - { - db_.Execute("DELETE FROM " + tableName); - } - - - bool SQLiteDatabaseWrapper::LookupParent(int64_t& parentId, - int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT parentId FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (!s.Step()) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - if (s.ColumnIsNull(0)) - { - return false; - } - else - { - parentId = s.ColumnInt(0); - return true; - } - } - - - ResourceType SQLiteDatabaseWrapper::GetResourceType(int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT resourceType FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (s.Step()) - { - return static_cast(s.ColumnInt(0)); - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - - std::string SQLiteDatabaseWrapper::GetPublicId(int64_t resourceId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT publicId FROM Resources WHERE internalId=?"); - s.BindInt64(0, resourceId); - - if (s.Step()) - { - return s.ColumnString(0); - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - - void SQLiteDatabaseWrapper::GetChanges(std::list& target /*out*/, - bool& done /*out*/, - int64_t since, - uint32_t maxResults) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes WHERE seq>? ORDER BY seq LIMIT ?"); - s.BindInt64(0, since); - s.BindInt(1, maxResults + 1); - GetChangesInternal(target, done, s, maxResults); - } - - - void SQLiteDatabaseWrapper::GetLastChange(std::list& target /*out*/) - { - bool done; // Ignored - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM Changes ORDER BY seq DESC LIMIT 1"); - GetChangesInternal(target, done, s, 1); - } - - - class SQLiteDatabaseWrapper::Transaction : public IDatabaseWrapper::ITransaction - { - private: - SQLiteDatabaseWrapper& that_; - std::unique_ptr transaction_; - int64_t initialDiskSize_; - - public: - Transaction(SQLiteDatabaseWrapper& that) : - that_(that), - transaction_(new SQLite::Transaction(that_.db_)) - { -#if defined(NDEBUG) - // Release mode - initialDiskSize_ = 0; -#else - // Debug mode - initialDiskSize_ = static_cast(that_.GetTotalCompressedSize()); -#endif - } - - virtual void Begin() - { - transaction_->Begin(); - } - - virtual void Rollback() - { - transaction_->Rollback(); - } - - virtual void Commit(int64_t fileSizeDelta /* only used in debug */) - { - transaction_->Commit(); - - assert(initialDiskSize_ + fileSizeDelta >= 0 && - initialDiskSize_ + fileSizeDelta == static_cast(that_.GetTotalCompressedSize())); - } - }; - - - IDatabaseWrapper::ITransaction* SQLiteDatabaseWrapper::StartTransaction() - { - return new Transaction(*this); - } - - - void SQLiteDatabaseWrapper::GetAllMetadata(std::map& target, - int64_t id) - { - target.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT type, value FROM Metadata WHERE id=?"); - s.BindInt64(0, id); - - while (s.Step()) - { - MetadataType key = static_cast(s.ColumnInt(0)); - target[key] = s.ColumnString(1); - } - } - - - void SQLiteDatabaseWrapper::SetGlobalProperty(GlobalProperty property, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO GlobalProperties VALUES(?, ?)"); - s.BindInt(0, property); - s.BindString(1, value); - s.Run(); - } - - - bool SQLiteDatabaseWrapper::LookupGlobalProperty(std::string& target, - GlobalProperty property) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM GlobalProperties WHERE property=?"); - s.BindInt(0, property); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - - int64_t SQLiteDatabaseWrapper::CreateResource(const std::string& publicId, - ResourceType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(NULL, ?, ?, NULL)"); - s.BindInt(0, type); - s.BindString(1, publicId); - s.Run(); - return db_.GetLastInsertRowId(); - } - - - bool SQLiteDatabaseWrapper::LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT internalId, resourceType FROM Resources WHERE publicId=?"); - s.BindString(0, publicId); - - if (!s.Step()) - { - return false; - } - else - { - id = s.ColumnInt(0); - type = static_cast(s.ColumnInt(1)); - - // Check whether there is a single resource with this public id - assert(!s.Step()); - - return true; - } - } - - - void SQLiteDatabaseWrapper::AttachChild(int64_t parent, - int64_t child) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "UPDATE Resources SET parentId = ? WHERE internalId = ?"); - s.BindInt64(0, parent); - s.BindInt64(1, child); - s.Run(); - } - - - void SQLiteDatabaseWrapper::SetMetadata(int64_t id, - MetadataType type, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT OR REPLACE INTO Metadata VALUES(?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, type); - s.BindString(2, value); - s.Run(); - } - - - void SQLiteDatabaseWrapper::DeleteMetadata(int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM Metadata WHERE id=? and type=?"); - s.BindInt64(0, id); - s.BindInt(1, type); - s.Run(); - } - - - bool SQLiteDatabaseWrapper::LookupMetadata(std::string& target, - int64_t id, - MetadataType type) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT value FROM Metadata WHERE id=? AND type=?"); - s.BindInt64(0, id); - s.BindInt(1, type); - - if (!s.Step()) - { - return false; - } - else - { - target = s.ColumnString(0); - return true; - } - } - - - void SQLiteDatabaseWrapper::AddAttachment(int64_t id, - const FileInfo& attachment) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, attachment.GetContentType()); - s.BindString(2, attachment.GetUuid()); - s.BindInt64(3, attachment.GetCompressedSize()); - s.BindInt64(4, attachment.GetUncompressedSize()); - s.BindInt(5, attachment.GetCompressionType()); - s.BindString(6, attachment.GetUncompressedMD5()); - s.BindString(7, attachment.GetCompressedMD5()); - s.Run(); - } - - - void SQLiteDatabaseWrapper::DeleteAttachment(int64_t id, - FileContentType attachment) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM AttachedFiles WHERE id=? AND fileType=?"); - s.BindInt64(0, id); - s.BindInt(1, attachment); - s.Run(); - } - - - void SQLiteDatabaseWrapper::ListAvailableAttachments(std::list& target, - int64_t id) - { - target.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT fileType FROM AttachedFiles WHERE id=?"); - s.BindInt64(0, id); - - while (s.Step()) - { - target.push_back(static_cast(s.ColumnInt(0))); - } - } - - bool SQLiteDatabaseWrapper::LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT uuid, uncompressedSize, compressionType, compressedSize, " - "uncompressedMD5, compressedMD5 FROM AttachedFiles WHERE id=? AND fileType=?"); - s.BindInt64(0, id); - s.BindInt(1, contentType); - - if (!s.Step()) - { - return false; - } - else - { - attachment = FileInfo(s.ColumnString(0), - contentType, - s.ColumnInt64(1), - s.ColumnString(4), - static_cast(s.ColumnInt(2)), - s.ColumnInt64(3), - s.ColumnString(5)); - return true; - } - } - - - void SQLiteDatabaseWrapper::ClearMainDicomTags(int64_t id) - { - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM DicomIdentifiers WHERE id=?"); - s.BindInt64(0, id); - s.Run(); - } - - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM MainDicomTags WHERE id=?"); - s.BindInt64(0, id); - s.Run(); - } - } - - - void SQLiteDatabaseWrapper::SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, tag.GetGroup()); - s.BindInt(2, tag.GetElement()); - s.BindString(3, value); - s.Run(); - } - - - void SQLiteDatabaseWrapper::SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO DicomIdentifiers VALUES(?, ?, ?, ?)"); - s.BindInt64(0, id); - s.BindInt(1, tag.GetGroup()); - s.BindInt(2, tag.GetElement()); - s.BindString(3, value); - s.Run(); - } - - - void SQLiteDatabaseWrapper::GetMainDicomTags(DicomMap& map, - int64_t id) - { - map.Clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT * FROM MainDicomTags WHERE id=?"); - s.BindInt64(0, id); - while (s.Step()) - { - map.SetValue(s.ColumnInt(1), - s.ColumnInt(2), - s.ColumnString(3), false); - } - } - - - void SQLiteDatabaseWrapper::GetChildrenPublicId(std::list& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.publicId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt64(0, id); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - void SQLiteDatabaseWrapper::GetChildrenInternalId(std::list& target, - int64_t id) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT a.internalId FROM Resources AS a, Resources AS b " - "WHERE a.parentId = b.internalId AND b.internalId = ?"); - s.BindInt64(0, id); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnInt64(0)); - } - } - - - void SQLiteDatabaseWrapper::LogChange(int64_t internalId, - const ServerIndexChange& change) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Changes VALUES(NULL, ?, ?, ?, ?)"); - s.BindInt(0, change.GetChangeType()); - s.BindInt64(1, internalId); - s.BindInt(2, change.GetResourceType()); - s.BindString(3, change.GetDate()); - s.Run(); - } - - - void SQLiteDatabaseWrapper::LogExportedResource(const ExportedResource& resource) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "INSERT INTO ExportedResources VALUES(NULL, ?, ?, ?, ?, ?, ?, ?, ?)"); - - s.BindInt(0, resource.GetResourceType()); - s.BindString(1, resource.GetPublicId()); - s.BindString(2, resource.GetModality()); - s.BindString(3, resource.GetPatientId()); - s.BindString(4, resource.GetStudyInstanceUid()); - s.BindString(5, resource.GetSeriesInstanceUid()); - s.BindString(6, resource.GetSopInstanceUid()); - s.BindString(7, resource.GetDate()); - s.Run(); - } - - - void SQLiteDatabaseWrapper::GetExportedResources(std::list& target, - bool& done, - int64_t since, - uint32_t maxResults) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM ExportedResources WHERE seq>? ORDER BY seq LIMIT ?"); - s.BindInt64(0, since); - s.BindInt(1, maxResults + 1); - GetExportedResourcesInternal(target, done, s, maxResults); - } - - - void SQLiteDatabaseWrapper::GetLastExportedResource(std::list& target) - { - bool done; // Ignored - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM ExportedResources ORDER BY seq DESC LIMIT 1"); - GetExportedResourcesInternal(target, done, s, 1); - } - - - uint64_t SQLiteDatabaseWrapper::GetTotalCompressedSize() - { - // Old SQL query that was used in Orthanc <= 1.5.0: - // SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(compressedSize) FROM AttachedFiles"); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT value FROM GlobalIntegers WHERE key=0"); - s.Run(); - return static_cast(s.ColumnInt64(0)); - } - - - uint64_t SQLiteDatabaseWrapper::GetTotalUncompressedSize() - { - // Old SQL query that was used in Orthanc <= 1.5.0: - // SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(uncompressedSize) FROM AttachedFiles"); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT value FROM GlobalIntegers WHERE key=1"); - s.Run(); - return static_cast(s.ColumnInt64(0)); - } - - - uint64_t SQLiteDatabaseWrapper::GetResourceCount(ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT COUNT(*) FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - if (!s.Step()) - { - return 0; - } - else - { - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - return c; - } - } - - - void SQLiteDatabaseWrapper::GetAllPublicIds(std::list& target, - ResourceType resourceType) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Resources WHERE resourceType=?"); - s.BindInt(0, resourceType); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - void SQLiteDatabaseWrapper::GetAllPublicIds(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit) - { - if (limit == 0) - { - target.clear(); - return; - } - - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT publicId FROM Resources WHERE " - "resourceType=? LIMIT ? OFFSET ?"); - s.BindInt(0, resourceType); - s.BindInt64(1, limit); - s.BindInt64(2, since); - - target.clear(); - while (s.Step()) - { - target.push_back(s.ColumnString(0)); - } - } - - - bool SQLiteDatabaseWrapper::SelectPatientToRecycle(int64_t& internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT patientId FROM PatientRecyclingOrder ORDER BY seq ASC LIMIT 1"); - - if (!s.Step()) - { - // No patient remaining or all the patients are protected - return false; - } - else - { - internalId = s.ColumnInt(0); - return true; - } - } - - - bool SQLiteDatabaseWrapper::SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT patientId FROM PatientRecyclingOrder " - "WHERE patientId != ? ORDER BY seq ASC LIMIT 1"); - s.BindInt64(0, patientIdToAvoid); - - if (!s.Step()) - { - // No patient remaining or all the patients are protected - return false; - } - else - { - internalId = s.ColumnInt(0); - return true; - } - } - - - bool SQLiteDatabaseWrapper::IsProtectedPatient(int64_t internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM PatientRecyclingOrder WHERE patientId = ?"); - s.BindInt64(0, internalId); - return !s.Step(); - } - - - void SQLiteDatabaseWrapper::SetProtectedPatient(int64_t internalId, - bool isProtected) - { - if (isProtected) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM PatientRecyclingOrder WHERE patientId=?"); - s.BindInt64(0, internalId); - s.Run(); - } - else if (IsProtectedPatient(internalId)) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO PatientRecyclingOrder VALUES(NULL, ?)"); - s.BindInt64(0, internalId); - s.Run(); - } - else - { - // Nothing to do: The patient is already unprotected - } - } - - - bool SQLiteDatabaseWrapper::IsExistingResource(int64_t internalId) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT * FROM Resources WHERE internalId=?"); - s.BindInt64(0, internalId); - return s.Step(); - } - - - bool SQLiteDatabaseWrapper::IsDiskSizeAbove(uint64_t threshold) - { - return GetTotalCompressedSize() > threshold; - } - - - - class SQLiteDatabaseWrapper::LookupFormatter : public ISqlLookupFormatter - { - private: - std::list values_; - - public: - virtual std::string GenerateParameter(const std::string& value) - { - values_.push_back(value); - return "?"; - } - - virtual std::string FormatResourceType(ResourceType level) - { - return boost::lexical_cast(level); - } - - virtual std::string FormatWildcardEscape() - { - return "ESCAPE '\\'"; - } - - void Bind(SQLite::Statement& statement) const - { - size_t pos = 0; - - for (std::list::const_iterator - it = values_.begin(); it != values_.end(); ++it, pos++) - { - statement.BindString(pos, *it); - } - } - }; - - - static void AnswerLookup(std::list& resourcesId, - std::list& instancesId, - SQLite::Connection& db, - ResourceType level) - { - resourcesId.clear(); - instancesId.clear(); - - std::unique_ptr statement; - - switch (level) - { - case ResourceType_Patient: - { - statement.reset( - new SQLite::Statement( - db, SQLITE_FROM_HERE, - "SELECT patients.publicId, instances.publicID FROM Lookup AS patients " - "INNER JOIN Resources studies ON patients.internalId=studies.parentId " - "INNER JOIN Resources series ON studies.internalId=series.parentId " - "INNER JOIN Resources instances ON series.internalId=instances.parentId " - "GROUP BY patients.publicId")); - - break; - } - - case ResourceType_Study: - { - statement.reset( - new SQLite::Statement( - db, SQLITE_FROM_HERE, - "SELECT studies.publicId, instances.publicID FROM Lookup AS studies " - "INNER JOIN Resources series ON studies.internalId=series.parentId " - "INNER JOIN Resources instances ON series.internalId=instances.parentId " - "GROUP BY studies.publicId")); - - break; - } - - case ResourceType_Series: - { - statement.reset( - new SQLite::Statement( - db, SQLITE_FROM_HERE, - "SELECT series.publicId, instances.publicID FROM Lookup AS series " - "INNER JOIN Resources instances ON series.internalId=instances.parentId " - "GROUP BY series.publicId")); - - break; - } - - case ResourceType_Instance: - { - statement.reset( - new SQLite::Statement( - db, SQLITE_FROM_HERE, "SELECT publicId, publicId FROM Lookup")); - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - assert(statement.get() != NULL); - - while (statement->Step()) - { - resourcesId.push_back(statement->ColumnString(0)); - instancesId.push_back(statement->ColumnString(1)); - } - } - - - void SQLiteDatabaseWrapper::ApplyLookupResources(std::list& resourcesId, - std::list* instancesId, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit) - { - LookupFormatter formatter; - - std::string sql; - LookupFormatter::Apply(sql, formatter, lookup, queryLevel, limit); - - sql = "CREATE TEMPORARY TABLE Lookup AS " + sql; - - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup"); - s.Run(); - } - - { - SQLite::Statement statement(db_, sql); - formatter.Bind(statement); - statement.Run(); - } - - if (instancesId != NULL) - { - AnswerLookup(resourcesId, *instancesId, db_, queryLevel); - } - else - { - resourcesId.clear(); - - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT publicId FROM Lookup"); - - while (s.Step()) - { - resourcesId.push_back(s.ColumnString(0)); - } - } - } - - - int64_t SQLiteDatabaseWrapper::GetLastChangeIndex() - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT seq FROM sqlite_sequence WHERE name='Changes'"); - - if (s.Step()) - { - int64_t c = s.ColumnInt(0); - assert(!s.Step()); - return c; - } - else - { - // No change has been recorded so far in the database - return 0; - } - } - - - void SQLiteDatabaseWrapper::TagMostRecentPatient(int64_t patient) - { - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "DELETE FROM PatientRecyclingOrder WHERE patientId=?"); - s.BindInt64(0, patient); - s.Run(); - - assert(db_.GetLastChangeCount() == 0 || - db_.GetLastChangeCount() == 1); - - if (db_.GetLastChangeCount() == 0) - { - // The patient was protected, there was nothing to delete from the recycling order - return; - } - } - - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "INSERT INTO PatientRecyclingOrder VALUES(NULL, ?)"); - s.BindInt64(0, patient); - s.Run(); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/SQLiteDatabaseWrapper.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,372 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IDatabaseWrapper.h" - -#include "../../Core/SQLite/Connection.h" -#include "Compatibility/ICreateInstance.h" -#include "Compatibility/IGetChildrenMetadata.h" -#include "Compatibility/ILookupResourceAndParent.h" -#include "Compatibility/ISetResourcesContent.h" - -namespace Orthanc -{ - namespace Internals - { - class SignalRemainingAncestor; - } - - /** - * This class manages an instance of the Orthanc SQLite database. It - * translates low-level requests into SQL statements. Mutual - * exclusion MUST be implemented at a higher level. - **/ - class SQLiteDatabaseWrapper : - public IDatabaseWrapper, - public Compatibility::ICreateInstance, - public Compatibility::IGetChildrenMetadata, - public Compatibility::ILookupResourceAndParent, - public Compatibility::ISetResourcesContent - { - private: - class Transaction; - class LookupFormatter; - - IDatabaseListener* listener_; - SQLite::Connection db_; - Internals::SignalRemainingAncestor* signalRemainingAncestor_; - unsigned int version_; - - void GetChangesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); - - void GetExportedResourcesInternal(std::list& target, - bool& done, - SQLite::Statement& s, - uint32_t maxResults); - - void ClearTable(const std::string& tableName); - - // Unused => could be removed - int GetGlobalIntegerProperty(GlobalProperty property, - int defaultValue); - - public: - SQLiteDatabaseWrapper(const std::string& path); - - SQLiteDatabaseWrapper(); - - virtual void Open() - ORTHANC_OVERRIDE; - - virtual void Close() - ORTHANC_OVERRIDE - { - db_.Close(); - } - - virtual void SetListener(IDatabaseListener& listener) - ORTHANC_OVERRIDE; - - virtual bool LookupParent(int64_t& parentId, - int64_t resourceId) - ORTHANC_OVERRIDE; - - virtual std::string GetPublicId(int64_t resourceId) - ORTHANC_OVERRIDE; - - virtual ResourceType GetResourceType(int64_t resourceId) - ORTHANC_OVERRIDE; - - virtual void DeleteResource(int64_t id) - ORTHANC_OVERRIDE; - - virtual void GetChanges(std::list& target /*out*/, - bool& done /*out*/, - int64_t since, - uint32_t maxResults) - ORTHANC_OVERRIDE; - - virtual void GetLastChange(std::list& target /*out*/) - ORTHANC_OVERRIDE; - - virtual IDatabaseWrapper::ITransaction* StartTransaction() - ORTHANC_OVERRIDE; - - virtual void FlushToDisk() - ORTHANC_OVERRIDE - { - db_.FlushToDisk(); - } - - virtual bool HasFlushToDisk() const - ORTHANC_OVERRIDE - { - return true; - } - - virtual void ClearChanges() - ORTHANC_OVERRIDE - { - ClearTable("Changes"); - } - - virtual void ClearExportedResources() - ORTHANC_OVERRIDE - { - ClearTable("ExportedResources"); - } - - virtual void GetAllMetadata(std::map& target, - int64_t id) - ORTHANC_OVERRIDE; - - virtual unsigned int GetDatabaseVersion() - ORTHANC_OVERRIDE - { - return version_; - } - - virtual void Upgrade(unsigned int targetVersion, - IStorageArea& storageArea) - ORTHANC_OVERRIDE; - - - /** - * The methods declared below are for unit testing only! - **/ - - const char* GetErrorMessage() const - { - return db_.GetErrorMessage(); - } - - void GetChildren(std::list& childrenPublicIds, - int64_t id); - - int64_t GetTableRecordCount(const std::string& table); - - bool GetParentPublicId(std::string& target, - int64_t id); - - - - /** - * Until Orthanc 1.4.0, the methods below were part of the - * "DatabaseWrapperBase" class, that is now placed in the - * graveyard. - **/ - - virtual void SetGlobalProperty(GlobalProperty property, - const std::string& value) - ORTHANC_OVERRIDE; - - virtual bool LookupGlobalProperty(std::string& target, - GlobalProperty property) - ORTHANC_OVERRIDE; - - virtual int64_t CreateResource(const std::string& publicId, - ResourceType type) - ORTHANC_OVERRIDE; - - virtual bool LookupResource(int64_t& id, - ResourceType& type, - const std::string& publicId) - ORTHANC_OVERRIDE; - - virtual void AttachChild(int64_t parent, - int64_t child) - ORTHANC_OVERRIDE; - - virtual void SetMetadata(int64_t id, - MetadataType type, - const std::string& value) - ORTHANC_OVERRIDE; - - virtual void DeleteMetadata(int64_t id, - MetadataType type) - ORTHANC_OVERRIDE; - - virtual bool LookupMetadata(std::string& target, - int64_t id, - MetadataType type) - ORTHANC_OVERRIDE; - - virtual void AddAttachment(int64_t id, - const FileInfo& attachment) - ORTHANC_OVERRIDE; - - virtual void DeleteAttachment(int64_t id, - FileContentType attachment) - ORTHANC_OVERRIDE; - - virtual void ListAvailableAttachments(std::list& target, - int64_t id) - ORTHANC_OVERRIDE; - - virtual bool LookupAttachment(FileInfo& attachment, - int64_t id, - FileContentType contentType) - ORTHANC_OVERRIDE; - - virtual void ClearMainDicomTags(int64_t id) - ORTHANC_OVERRIDE; - - virtual void SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value) - ORTHANC_OVERRIDE; - - virtual void SetIdentifierTag(int64_t id, - const DicomTag& tag, - const std::string& value) - ORTHANC_OVERRIDE; - - virtual void GetMainDicomTags(DicomMap& map, - int64_t id) - ORTHANC_OVERRIDE; - - virtual void GetChildrenPublicId(std::list& target, - int64_t id) - ORTHANC_OVERRIDE; - - virtual void GetChildrenInternalId(std::list& target, - int64_t id) - ORTHANC_OVERRIDE; - - virtual void LogChange(int64_t internalId, - const ServerIndexChange& change) - ORTHANC_OVERRIDE; - - virtual void LogExportedResource(const ExportedResource& resource) - ORTHANC_OVERRIDE; - - virtual void GetExportedResources(std::list& target /*out*/, - bool& done /*out*/, - int64_t since, - uint32_t maxResults) - ORTHANC_OVERRIDE; - - virtual void GetLastExportedResource(std::list& target /*out*/) - ORTHANC_OVERRIDE; - - virtual uint64_t GetTotalCompressedSize() - ORTHANC_OVERRIDE; - - virtual uint64_t GetTotalUncompressedSize() - ORTHANC_OVERRIDE; - - virtual uint64_t GetResourceCount(ResourceType resourceType) - ORTHANC_OVERRIDE; - - virtual void GetAllPublicIds(std::list& target, - ResourceType resourceType) - ORTHANC_OVERRIDE; - - virtual void GetAllPublicIds(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit) - ORTHANC_OVERRIDE; - - virtual bool SelectPatientToRecycle(int64_t& internalId) - ORTHANC_OVERRIDE; - - virtual bool SelectPatientToRecycle(int64_t& internalId, - int64_t patientIdToAvoid) - ORTHANC_OVERRIDE; - - virtual bool IsProtectedPatient(int64_t internalId) - ORTHANC_OVERRIDE; - - virtual void SetProtectedPatient(int64_t internalId, - bool isProtected) - ORTHANC_OVERRIDE; - - virtual bool IsExistingResource(int64_t internalId) - ORTHANC_OVERRIDE; - - virtual bool IsDiskSizeAbove(uint64_t threshold) - ORTHANC_OVERRIDE; - - virtual void ApplyLookupResources(std::list& resourcesId, - std::list* instancesId, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit) - ORTHANC_OVERRIDE; - - virtual bool CreateInstance(CreateInstanceResult& result, - int64_t& instanceId, - const std::string& patient, - const std::string& study, - const std::string& series, - const std::string& instance) - ORTHANC_OVERRIDE - { - return ICreateInstance::Apply - (*this, result, instanceId, patient, study, series, instance); - } - - virtual void SetResourcesContent(const Orthanc::ResourcesContent& content) - ORTHANC_OVERRIDE - { - ISetResourcesContent::Apply(*this, content); - } - - virtual void GetChildrenMetadata(std::list& target, - int64_t resourceId, - MetadataType metadata) - ORTHANC_OVERRIDE - { - IGetChildrenMetadata::Apply(*this, target, resourceId, metadata); - } - - virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE; - - virtual void TagMostRecentPatient(int64_t patient) ORTHANC_OVERRIDE; - - virtual bool LookupResourceAndParent(int64_t& id, - ResourceType& type, - std::string& parentPublicId, - const std::string& publicId) - ORTHANC_OVERRIDE - { - return ILookupResourceAndParent::Apply(*this, id, type, parentPublicId, publicId); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade3To4.sql orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade3To4.sql --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade3To4.sql 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade3To4.sql 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ --- This SQLite script updates the version of the Orthanc database from 3 to 4. - --- Add 2 new columns at "AttachedFiles" - -ALTER TABLE AttachedFiles ADD COLUMN uncompressedMD5 TEXT; -ALTER TABLE AttachedFiles ADD COLUMN compressedMD5 TEXT; - --- Update the "AttachedFileDeleted" trigger - -DROP TRIGGER AttachedFileDeleted; - -CREATE TRIGGER AttachedFileDeleted -AFTER DELETE ON AttachedFiles -BEGIN - SELECT SignalFileDeleted(old.uuid, old.fileType, old.uncompressedSize, - old.compressionType, old.compressedSize, - -- These 2 arguments are new in Orthanc 0.7.3 (database v4) - old.uncompressedMD5, old.compressedMD5); -END; - --- Change the database version --- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration - -UPDATE GlobalProperties SET value="4" WHERE property=1; diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade4To5.sql orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade4To5.sql --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade4To5.sql 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Database/Upgrade4To5.sql 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ --- This SQLite script updates the version of the Orthanc database from 4 to 5. - - --- Remove 2 indexes to speed up - -DROP INDEX MainDicomTagsIndex2; -DROP INDEX MainDicomTagsIndexValues; - - --- Add a new table to index the DICOM identifiers - -CREATE TABLE DicomIdentifiers( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - tagGroup INTEGER, - tagElement INTEGER, - value TEXT, - PRIMARY KEY(id, tagGroup, tagElement) - ); - -CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id); -CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement); -CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY); - - --- Migrate data from MainDicomTags to MainResourcesTags and MainInstancesTags - -INSERT INTO DicomIdentifiers SELECT * FROM MainDicomTags - WHERE ((tagGroup = 16 AND tagElement = 32) OR -- PatientID (0x0010, 0x0020) - (tagGroup = 32 AND tagElement = 13) OR -- StudyInstanceUID (0x0020, 0x000d) - (tagGroup = 8 AND tagElement = 80) OR -- AccessionNumber (0x0008, 0x0050) - (tagGroup = 32 AND tagElement = 14) OR -- SeriesInstanceUID (0x0020, 0x000e) - (tagGroup = 8 AND tagElement = 24)); -- SOPInstanceUID (0x0008, 0x0018) - -DELETE FROM MainDicomTags - WHERE ((tagGroup = 16 AND tagElement = 32) OR -- PatientID (0x0010, 0x0020) - (tagGroup = 32 AND tagElement = 13) OR -- StudyInstanceUID (0x0020, 0x000d) - (tagGroup = 8 AND tagElement = 80) OR -- AccessionNumber (0x0008, 0x0050) - (tagGroup = 32 AND tagElement = 14) OR -- SeriesInstanceUID (0x0020, 0x000e) - (tagGroup = 8 AND tagElement = 24)); -- SOPInstanceUID (0x0008, 0x0018) - - --- Upgrade the "ResourceDeleted" trigger - -DROP TRIGGER ResourceDeleted; -DROP TRIGGER ResourceDeletedParentCleaning; - -CREATE TRIGGER ResourceDeleted -AFTER DELETE ON Resources -BEGIN - SELECT SignalResourceDeleted(old.publicId, old.resourceType); - SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) - FROM Resources AS parent WHERE internalId = old.parentId; -END; - -CREATE TRIGGER ResourceDeletedParentCleaning -AFTER DELETE ON Resources -FOR EACH ROW WHEN (SELECT COUNT(*) FROM Resources WHERE parentId = old.parentId) = 0 -BEGIN - DELETE FROM Resources WHERE internalId = old.parentId; -END; - - --- Change the database version --- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration - -UPDATE GlobalProperties SET value="5" WHERE property=1; diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "DicomInstanceOrigin.h" - -#include "../Core/OrthancException.h" -#include "../Core/SerializationToolbox.h" - -namespace Orthanc -{ - void DicomInstanceOrigin::Format(Json::Value& result) const - { - result = Json::objectValue; - result["RequestOrigin"] = EnumerationToString(origin_); - - switch (origin_) - { - case RequestOrigin_Unknown: - { - // None of the methods "SetDicomProtocolOrigin()", "SetHttpOrigin()", - // "SetLuaOrigin()" or "SetPluginsOrigin()" was called! - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - case RequestOrigin_DicomProtocol: - { - result["RemoteIp"] = remoteIp_; - result["RemoteAet"] = dicomRemoteAet_; - result["CalledAet"] = dicomCalledAet_; - break; - } - - case RequestOrigin_RestApi: - { - result["RemoteIp"] = remoteIp_; - result["Username"] = httpUsername_; - break; - } - - case RequestOrigin_Lua: - case RequestOrigin_Plugins: - { - // No additional information available for these kinds of requests - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - DicomInstanceOrigin DicomInstanceOrigin::FromDicomProtocol(const char* remoteIp, - const char* remoteAet, - const char* calledAet) - { - DicomInstanceOrigin result(RequestOrigin_DicomProtocol); - result.remoteIp_ = remoteIp; - result.dicomRemoteAet_ = remoteAet; - result.dicomCalledAet_ = calledAet; - return result; - } - - DicomInstanceOrigin DicomInstanceOrigin::FromRest(const RestApiCall& call) - { - DicomInstanceOrigin result(call.GetRequestOrigin()); - - if (result.origin_ == RequestOrigin_RestApi) - { - result.remoteIp_ = call.GetRemoteIp(); - result.httpUsername_ = call.GetUsername(); - } - - return result; - } - - DicomInstanceOrigin DicomInstanceOrigin::FromHttp(const char* remoteIp, - const char* username) - { - DicomInstanceOrigin result(RequestOrigin_RestApi); - result.remoteIp_ = remoteIp; - result.httpUsername_ = username; - return result; - } - - const char* DicomInstanceOrigin::GetRemoteAetC() const - { - if (origin_ == RequestOrigin_DicomProtocol) - { - return dicomRemoteAet_.c_str(); - } - else - { - return ""; - } - } - - bool DicomInstanceOrigin::LookupRemoteAet(std::string& result) const - { - if (origin_ == RequestOrigin_DicomProtocol) - { - result = dicomRemoteAet_.c_str(); - return true; - } - else - { - return false; - } - } - - bool DicomInstanceOrigin::LookupRemoteIp(std::string& result) const - { - if (origin_ == RequestOrigin_DicomProtocol || - origin_ == RequestOrigin_RestApi) - { - result = remoteIp_; - return true; - } - else - { - return false; - } - } - - bool DicomInstanceOrigin::LookupCalledAet(std::string& result) const - { - if (origin_ == RequestOrigin_DicomProtocol) - { - result = dicomCalledAet_; - return true; - } - else - { - return false; - } - } - - bool DicomInstanceOrigin::LookupHttpUsername(std::string& result) const - { - if (origin_ == RequestOrigin_RestApi) - { - result = httpUsername_; - return true; - } - else - { - return false; - } - } - - - - static const char* ORIGIN = "Origin"; - static const char* REMOTE_IP = "RemoteIP"; - static const char* DICOM_REMOTE_AET = "RemoteAET"; - static const char* DICOM_CALLED_AET = "CalledAET"; - static const char* HTTP_USERNAME = "Username"; - - - DicomInstanceOrigin::DicomInstanceOrigin(const Json::Value& serialized) - { - origin_ = StringToRequestOrigin(SerializationToolbox::ReadString(serialized, ORIGIN)); - remoteIp_ = SerializationToolbox::ReadString(serialized, REMOTE_IP); - dicomRemoteAet_ = SerializationToolbox::ReadString(serialized, DICOM_REMOTE_AET); - dicomCalledAet_ = SerializationToolbox::ReadString(serialized, DICOM_CALLED_AET); - httpUsername_ = SerializationToolbox::ReadString(serialized, HTTP_USERNAME); - } - - - void DicomInstanceOrigin::Serialize(Json::Value& result) const - { - result = Json::objectValue; - result[ORIGIN] = EnumerationToString(origin_); - result[REMOTE_IP] = remoteIp_; - result[DICOM_REMOTE_AET] = dicomRemoteAet_; - result[DICOM_CALLED_AET] = dicomCalledAet_; - result[HTTP_USERNAME] = httpUsername_; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceOrigin.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/RestApi/RestApiCall.h" - -namespace Orthanc -{ - class DicomInstanceOrigin - { - private: - RequestOrigin origin_; - std::string remoteIp_; - std::string dicomRemoteAet_; - std::string dicomCalledAet_; - std::string httpUsername_; - - DicomInstanceOrigin(RequestOrigin origin) : - origin_(origin) - { - } - - public: - DicomInstanceOrigin() : - origin_(RequestOrigin_Unknown) - { - } - - DicomInstanceOrigin(const Json::Value& serialized); - - static DicomInstanceOrigin FromDicomProtocol(const char* remoteIp, - const char* remoteAet, - const char* calledAet); - - static DicomInstanceOrigin FromRest(const RestApiCall& call); - - static DicomInstanceOrigin FromHttp(const char* remoteIp, - const char* username); - - static DicomInstanceOrigin FromLua() - { - return DicomInstanceOrigin(RequestOrigin_Lua); - } - - static DicomInstanceOrigin FromPlugins() - { - return DicomInstanceOrigin(RequestOrigin_Plugins); - } - - RequestOrigin GetRequestOrigin() const - { - return origin_; - } - - const char* GetRemoteAetC() const; - - bool LookupRemoteAet(std::string& result) const; - - bool LookupRemoteIp(std::string& result) const; - - bool LookupCalledAet(std::string& result) const; - - bool LookupHttpUsername(std::string& result) const; - - void Format(Json::Value& result) const; - - void Serialize(Json::Value& result) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,508 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "DicomInstanceToStore.h" - -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/DicomParsing/ParsedDicomFile.h" -#include "../Core/Logging.h" -#include "../Core/OrthancException.h" - -#include -#include - - -namespace Orthanc -{ - // Anonymous namespace to avoid clashes between compilation modules - namespace - { - template - class SmartContainer - { - private: - T* content_; - bool toDelete_; - bool isReadOnly_; - - void Deallocate() - { - if (content_ && toDelete_) - { - delete content_; - toDelete_ = false; - content_ = NULL; - } - } - - public: - SmartContainer() : content_(NULL), toDelete_(false), isReadOnly_(true) - { - } - - ~SmartContainer() - { - Deallocate(); - } - - void Allocate() - { - Deallocate(); - content_ = new T; - toDelete_ = true; - isReadOnly_ = false; - } - - void TakeOwnership(T* content) - { - if (content == NULL) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - Deallocate(); - content_ = content; - toDelete_ = true; - isReadOnly_ = false; - } - - void SetReference(T& content) // Read and write assign, without transfering ownership - { - Deallocate(); - content_ = &content; - toDelete_ = false; - isReadOnly_ = false; - } - - void SetConstReference(const T& content) // Read-only assign, without transfering ownership - { - Deallocate(); - content_ = &const_cast(content); - toDelete_ = false; - isReadOnly_ = true; - } - - bool HasContent() const - { - return content_ != NULL; - } - - T& GetContent() - { - if (content_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (isReadOnly_) - { - throw OrthancException(ErrorCode_ReadOnly); - } - - return *content_; - } - - const T& GetConstContent() const - { - if (content_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - return *content_; - } - }; - } - - - class DicomInstanceToStore::PImpl - { - public: - DicomInstanceOrigin origin_; - bool hasBuffer_; - std::unique_ptr ownBuffer_; - const void* bufferData_; - size_t bufferSize_; - SmartContainer parsed_; - SmartContainer summary_; - SmartContainer json_; - MetadataMap metadata_; - - PImpl() : - hasBuffer_(false), - bufferData_(NULL), - bufferSize_(0) - { - } - - private: - std::unique_ptr hasher_; - - void ParseDicomFile() - { - if (!parsed_.HasContent()) - { - if (!hasBuffer_) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (ownBuffer_.get() != NULL) - { - parsed_.TakeOwnership(new ParsedDicomFile(*ownBuffer_)); - } - else - { - parsed_.TakeOwnership(new ParsedDicomFile(bufferData_, bufferSize_)); - } - } - } - - void ComputeMissingInformation() - { - if (hasBuffer_ && - summary_.HasContent() && - json_.HasContent()) - { - // Fine, everything is available - return; - } - - if (!hasBuffer_) - { - if (!parsed_.HasContent()) - { - if (!summary_.HasContent()) - { - throw OrthancException(ErrorCode_NotImplemented); - } - else - { - parsed_.TakeOwnership(new ParsedDicomFile(summary_.GetConstContent(), - GetDefaultDicomEncoding(), - false /* be strict */)); - } - } - - // Serialize the parsed DICOM file - ownBuffer_.reset(new std::string); - if (!FromDcmtkBridge::SaveToMemoryBuffer(*ownBuffer_, - *parsed_.GetContent().GetDcmtkObject().getDataset())) - { - throw OrthancException(ErrorCode_InternalError, - "Unable to serialize a DICOM file to a memory buffer"); - } - - hasBuffer_ = true; - } - - if (summary_.HasContent() && - json_.HasContent()) - { - return; - } - - // At this point, we know that the DICOM file is available as a - // memory buffer, but that its summary or its JSON version is - // missing - - ParseDicomFile(); - assert(parsed_.HasContent()); - - // At this point, we have parsed the DICOM file - - if (!summary_.HasContent()) - { - summary_.Allocate(); - FromDcmtkBridge::ExtractDicomSummary(summary_.GetContent(), - *parsed_.GetContent().GetDcmtkObject().getDataset()); - } - - if (!json_.HasContent()) - { - json_.Allocate(); - - std::set ignoreTagLength; - FromDcmtkBridge::ExtractDicomAsJson(json_.GetContent(), - *parsed_.GetContent().GetDcmtkObject().getDataset(), - ignoreTagLength); - } - } - - - public: - void SetBuffer(const void* data, - size_t size) - { - ownBuffer_.reset(NULL); - bufferData_ = data; - bufferSize_ = size; - hasBuffer_ = true; - } - - const void* GetBufferData() - { - ComputeMissingInformation(); - - if (!hasBuffer_) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (ownBuffer_.get() != NULL) - { - if (ownBuffer_->empty()) - { - return NULL; - } - else - { - return ownBuffer_->c_str(); - } - } - else - { - return bufferData_; - } - } - - - size_t GetBufferSize() - { - ComputeMissingInformation(); - - if (!hasBuffer_) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (ownBuffer_.get() != NULL) - { - return ownBuffer_->size(); - } - else - { - return bufferSize_; - } - } - - - const DicomMap& GetSummary() - { - ComputeMissingInformation(); - - if (!summary_.HasContent()) - { - throw OrthancException(ErrorCode_InternalError); - } - - return summary_.GetConstContent(); - } - - - const Json::Value& GetJson() - { - ComputeMissingInformation(); - - if (!json_.HasContent()) - { - throw OrthancException(ErrorCode_InternalError); - } - - return json_.GetConstContent(); - } - - - DicomInstanceHasher& GetHasher() - { - if (hasher_.get() == NULL) - { - hasher_.reset(new DicomInstanceHasher(GetSummary())); - } - - if (hasher_.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - return *hasher_; - } - - - bool LookupTransferSyntax(std::string& result) - { - ComputeMissingInformation(); - - DicomMap header; - if (DicomMap::ParseDicomMetaInformation(header, GetBufferData(), GetBufferSize())) - { - const DicomValue* value = header.TestAndGetValue(DICOM_TAG_TRANSFER_SYNTAX_UID); - if (value != NULL && - !value->IsBinary() && - !value->IsNull()) - { - result = Toolbox::StripSpaces(value->GetContent()); - return true; - } - } - - return false; - } - - - ParsedDicomFile& GetParsedDicomFile() - { - ComputeMissingInformation(); - ParseDicomFile(); - - if (parsed_.HasContent()) - { - return parsed_.GetContent(); - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - }; - - - DicomInstanceToStore::DicomInstanceToStore() : - pimpl_(new PImpl) - { - } - - - void DicomInstanceToStore::SetOrigin(const DicomInstanceOrigin& origin) - { - pimpl_->origin_ = origin; - } - - - const DicomInstanceOrigin& DicomInstanceToStore::GetOrigin() const - { - return pimpl_->origin_; - } - - - void DicomInstanceToStore::SetBuffer(const void* dicom, - size_t size) - { - pimpl_->SetBuffer(dicom, size); - } - - - void DicomInstanceToStore::SetParsedDicomFile(ParsedDicomFile& parsed) - { - pimpl_->parsed_.SetReference(parsed); - } - - - void DicomInstanceToStore::SetSummary(const DicomMap& summary) - { - pimpl_->summary_.SetConstReference(summary); - } - - - void DicomInstanceToStore::SetJson(const Json::Value& json) - { - pimpl_->json_.SetConstReference(json); - } - - - const DicomInstanceToStore::MetadataMap& DicomInstanceToStore::GetMetadata() const - { - return pimpl_->metadata_; - } - - - DicomInstanceToStore::MetadataMap& DicomInstanceToStore::GetMetadata() - { - return pimpl_->metadata_; - } - - - void DicomInstanceToStore::AddMetadata(ResourceType level, - MetadataType metadata, - const std::string& value) - { - pimpl_->metadata_[std::make_pair(level, metadata)] = value; - } - - - const void* DicomInstanceToStore::GetBufferData() const - { - return const_cast(*pimpl_).GetBufferData(); - } - - - size_t DicomInstanceToStore::GetBufferSize() const - { - return const_cast(*pimpl_).GetBufferSize(); - } - - - const DicomMap& DicomInstanceToStore::GetSummary() - { - return pimpl_->GetSummary(); - } - - - const Json::Value& DicomInstanceToStore::GetJson() const - { - return const_cast(*pimpl_).GetJson(); - } - - - bool DicomInstanceToStore::LookupTransferSyntax(std::string& result) const - { - return const_cast(*pimpl_).LookupTransferSyntax(result); - } - - - DicomInstanceHasher& DicomInstanceToStore::GetHasher() - { - return pimpl_->GetHasher(); - } - - bool DicomInstanceToStore::HasPixelData() const - { - return const_cast(*pimpl_).GetParsedDicomFile().HasTag(DICOM_TAG_PIXEL_DATA); - } - - ParsedDicomFile& DicomInstanceToStore::GetParsedDicomFile() const - { - return const_cast(*pimpl_).GetParsedDicomFile(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/DicomInstanceToStore.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,98 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/DicomFormat/DicomInstanceHasher.h" -#include "../Core/DicomFormat/DicomMap.h" -#include "DicomInstanceOrigin.h" -#include "ServerEnumerations.h" - -#include - -namespace Orthanc -{ - class ParsedDicomFile; - - class DicomInstanceToStore : public boost::noncopyable - { - public: - typedef std::map, std::string> MetadataMap; - - private: - class PImpl; - boost::shared_ptr pimpl_; - - public: - DicomInstanceToStore(); - - void SetOrigin(const DicomInstanceOrigin& origin); - - const DicomInstanceOrigin& GetOrigin() const; - - // WARNING: The buffer is not copied, it must not be removed as - // long as the "DicomInstanceToStore" object is alive - void SetBuffer(const void* dicom, - size_t size); - - void SetParsedDicomFile(ParsedDicomFile& parsed); - - void SetSummary(const DicomMap& summary); - - void SetJson(const Json::Value& json); - - const MetadataMap& GetMetadata() const; - - MetadataMap& GetMetadata(); - - void AddMetadata(ResourceType level, - MetadataType metadata, - const std::string& value); - - const void* GetBufferData() const; - - size_t GetBufferSize() const; - - const DicomMap& GetSummary(); - - const Json::Value& GetJson() const; - - bool LookupTransferSyntax(std::string& result) const; - - DicomInstanceHasher& GetHasher(); - - bool HasPixelData() const; - - ParsedDicomFile& GetParsedDicomFile() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "ExportedResource.h" - -#include "../Core/OrthancException.h" - -namespace Orthanc -{ - void ExportedResource::Format(Json::Value& item) const - { - item = Json::objectValue; - item["Seq"] = static_cast(seq_); - item["ResourceType"] = EnumerationToString(resourceType_); - item["ID"] = publicId_; - item["Path"] = GetBasePath(resourceType_, publicId_); - item["RemoteModality"] = modality_; - item["Date"] = date_; - - // WARNING: Do not add "break" below and do not reorder the case items! - switch (resourceType_) - { - case ResourceType_Instance: - item["SOPInstanceUID"] = sopInstanceUid_; - - case ResourceType_Series: - item["SeriesInstanceUID"] = seriesInstanceUid_; - - case ResourceType_Study: - item["StudyInstanceUID"] = studyInstanceUid_; - - case ResourceType_Patient: - item["PatientID"] = patientId_; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ExportedResource.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,126 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ServerEnumerations.h" -#include "../Core/Toolbox.h" - -#include -#include - -namespace Orthanc -{ - class ExportedResource - { - private: - int64_t seq_; - ResourceType resourceType_; - std::string publicId_; - std::string modality_; - std::string date_; - std::string patientId_; - std::string studyInstanceUid_; - std::string seriesInstanceUid_; - std::string sopInstanceUid_; - - public: - ExportedResource(int64_t seq, - ResourceType resourceType, - const std::string& publicId, - const std::string& modality, - const std::string& date, - const std::string& patientId, - const std::string& studyInstanceUid, - const std::string& seriesInstanceUid, - const std::string& sopInstanceUid) : - seq_(seq), - resourceType_(resourceType), - publicId_(publicId), - modality_(modality), - date_(date), - patientId_(patientId), - studyInstanceUid_(studyInstanceUid), - seriesInstanceUid_(seriesInstanceUid), - sopInstanceUid_(sopInstanceUid) - { - } - - int64_t GetSeq() const - { - return seq_; - } - - ResourceType GetResourceType() const - { - return resourceType_; - } - - const std::string& GetPublicId() const - { - return publicId_; - } - - const std::string& GetModality() const - { - return modality_; - } - - const std::string& GetDate() const - { - return date_; - } - - const std::string& GetPatientId() const - { - return patientId_; - } - - const std::string& GetStudyInstanceUid() const - { - return studyInstanceUid_; - } - - const std::string& GetSeriesInstanceUid() const - { - return seriesInstanceUid_; - } - - const std::string& GetSopInstanceUid() const - { - return sopInstanceUid_; - } - - void Format(Json::Value& item) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IDicomImageDecoder.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IDicomImageDecoder.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IDicomImageDecoder.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IDicomImageDecoder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/Images/ImageAccessor.h" - -#include - -namespace Orthanc -{ - class IDicomImageDecoder : public boost::noncopyable - { - public: - virtual ~IDicomImageDecoder() - { - } - - virtual ImageAccessor* Decode(const void* dicom, - size_t size, - unsigned int frame) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IServerListener.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IServerListener.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IServerListener.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/IServerListener.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomInstanceToStore.h" -#include "ServerIndexChange.h" - -#include - -namespace Orthanc -{ - class IServerListener : public boost::noncopyable - { - public: - virtual ~IServerListener() - { - } - - virtual void SignalStoredInstance(const std::string& publicId, - const DicomInstanceToStore& instance, - const Json::Value& simplifiedTags) = 0; - - virtual void SignalChange(const ServerIndexChange& change) = 0; - - virtual bool FilterIncomingInstance(const DicomInstanceToStore& instance, - const Json::Value& simplified) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,946 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "LuaScripting.h" - -#include "OrthancConfiguration.h" -#include "OrthancRestApi/OrthancRestApi.h" -#include "ServerContext.h" - -#include "../Core/HttpServer/StringHttpOutput.h" -#include "../Core/Logging.h" -#include "../Core/Lua/LuaFunctionCall.h" - -#include - - -namespace Orthanc -{ - class LuaScripting::IEvent : public IDynamicObject - { - public: - virtual void Apply(LuaScripting& lock) = 0; - }; - - - class LuaScripting::OnStoredInstanceEvent : public LuaScripting::IEvent - { - private: - std::string instanceId_; - Json::Value simplifiedTags_; - Json::Value metadata_; - Json::Value origin_; - - public: - OnStoredInstanceEvent(const std::string& instanceId, - const Json::Value& simplifiedTags, - const Json::Value& metadata, - const DicomInstanceToStore& instance) : - instanceId_(instanceId), - simplifiedTags_(simplifiedTags), - metadata_(metadata) - { - instance.GetOrigin().Format(origin_); - } - - virtual void Apply(LuaScripting& that) - { - static const char* NAME = "OnStoredInstance"; - - LuaScripting::Lock lock(that); - - if (lock.GetLua().IsExistingFunction(NAME)) - { - that.InitializeJob(); - - LuaFunctionCall call(lock.GetLua(), NAME); - call.PushString(instanceId_); - call.PushJson(simplifiedTags_); - call.PushJson(metadata_); - call.PushJson(origin_); - call.Execute(); - - that.SubmitJob(); - } - } - }; - - - class LuaScripting::ExecuteEvent : public LuaScripting::IEvent - { - private: - std::string command_; - - public: - ExecuteEvent(const std::string& command) : - command_(command) - { - } - - virtual void Apply(LuaScripting& that) - { - LuaScripting::Lock lock(that); - - if (lock.GetLua().IsExistingFunction(command_.c_str())) - { - LuaFunctionCall call(lock.GetLua(), command_.c_str()); - call.Execute(); - } - } - }; - - - class LuaScripting::StableResourceEvent : public LuaScripting::IEvent - { - private: - ServerIndexChange change_; - - public: - StableResourceEvent(const ServerIndexChange& change) : - change_(change) - { - } - - virtual void Apply(LuaScripting& that) - { - const char* name; - - switch (change_.GetChangeType()) - { - case ChangeType_StablePatient: - name = "OnStablePatient"; - break; - - case ChangeType_StableStudy: - name = "OnStableStudy"; - break; - - case ChangeType_StableSeries: - name = "OnStableSeries"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - { - // Avoid unnecessary calls to the database if there's no Lua callback - LuaScripting::Lock lock(that); - - if (!lock.GetLua().IsExistingFunction(name)) - { - return; - } - } - - Json::Value tags; - - if (that.context_.GetIndex().LookupResource(tags, change_.GetPublicId(), change_.GetResourceType())) - { - std::map metadata; - that.context_.GetIndex().GetAllMetadata(metadata, change_.GetPublicId()); - - Json::Value formattedMetadata = Json::objectValue; - - for (std::map::const_iterator - it = metadata.begin(); it != metadata.end(); ++it) - { - std::string key = EnumerationToString(it->first); - formattedMetadata[key] = it->second; - } - - { - LuaScripting::Lock lock(that); - - if (lock.GetLua().IsExistingFunction(name)) - { - that.InitializeJob(); - - LuaFunctionCall call(lock.GetLua(), name); - call.PushString(change_.GetPublicId()); - call.PushJson(tags["MainDicomTags"]); - call.PushJson(formattedMetadata); - call.Execute(); - - that.SubmitJob(); - } - } - } - } - }; - - - class LuaScripting::JobEvent : public LuaScripting::IEvent - { - public: - enum Type - { - Type_Failure, - Type_Submitted, - Type_Success - }; - - private: - Type type_; - std::string jobId_; - - public: - JobEvent(Type type, - const std::string& jobId) : - type_(type), - jobId_(jobId) - { - } - - virtual void Apply(LuaScripting& that) - { - std::string functionName; - - switch (type_) - { - case Type_Failure: - functionName = "OnJobFailure"; - break; - - case Type_Submitted: - functionName = "OnJobSubmitted"; - break; - - case Type_Success: - functionName = "OnJobSuccess"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - { - LuaScripting::Lock lock(that); - - if (lock.GetLua().IsExistingFunction(functionName.c_str())) - { - LuaFunctionCall call(lock.GetLua(), functionName.c_str()); - call.PushString(jobId_); - call.Execute(); - } - } - } - }; - - - class LuaScripting::DeleteEvent : public LuaScripting::IEvent - { - private: - ResourceType level_; - std::string publicId_; - - public: - DeleteEvent(ResourceType level, - const std::string& publicId) : - level_(level), - publicId_(publicId) - { - } - - virtual void Apply(LuaScripting& that) - { - std::string functionName; - - switch (level_) - { - case ResourceType_Patient: - functionName = "OnDeletedPatient"; - break; - - case ResourceType_Study: - functionName = "OnDeletedStudy"; - break; - - case ResourceType_Series: - functionName = "OnDeletedSeries"; - break; - - case ResourceType_Instance: - functionName = "OnDeletedInstance"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - { - LuaScripting::Lock lock(that); - - if (lock.GetLua().IsExistingFunction(functionName.c_str())) - { - LuaFunctionCall call(lock.GetLua(), functionName.c_str()); - call.PushString(publicId_); - call.Execute(); - } - } - } - }; - - - class LuaScripting::UpdateEvent : public LuaScripting::IEvent - { - private: - ResourceType level_; - std::string publicId_; - - public: - UpdateEvent(ResourceType level, - const std::string& publicId) : - level_(level), - publicId_(publicId) - { - } - - virtual void Apply(LuaScripting& that) - { - std::string functionName; - - switch (level_) - { - case ResourceType_Patient: - functionName = "OnUpdatedPatient"; - break; - - case ResourceType_Study: - functionName = "OnUpdatedStudy"; - break; - - case ResourceType_Series: - functionName = "OnUpdatedSeries"; - break; - - case ResourceType_Instance: - functionName = "OnUpdatedInstance"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - { - LuaScripting::Lock lock(that); - - if (lock.GetLua().IsExistingFunction(functionName.c_str())) - { - LuaFunctionCall call(lock.GetLua(), functionName.c_str()); - call.PushString(publicId_); - call.Execute(); - } - } - } - }; - - - ServerContext* LuaScripting::GetServerContext(lua_State *state) - { - const void* value = LuaContext::GetGlobalVariable(state, "_ServerContext"); - return const_cast(reinterpret_cast(value)); - } - - - // Syntax in Lua: RestApiGet(uri, builtin) - int LuaScripting::RestApiGet(lua_State *state) - { - ServerContext* serverContext = GetServerContext(state); - if (serverContext == NULL) - { - LOG(ERROR) << "Lua: The Orthanc API is unavailable"; - lua_pushnil(state); - return 1; - } - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if (nArgs < 1 || nArgs > 3 || - !lua_isstring(state, 1) || // URI - (nArgs >= 2 && !lua_isboolean(state, 2))) // Restrict to built-in API? - { - LOG(ERROR) << "Lua: Bad parameters to RestApiGet()"; - lua_pushnil(state); - return 1; - } - - const char* uri = lua_tostring(state, 1); - bool builtin = (nArgs == 2 ? lua_toboolean(state, 2) != 0 : false); - - std::map headers; - LuaContext::GetDictionaryArgument(headers, state, 3, true /* HTTP header key to lower case */); - - try - { - std::string result; - if (HttpToolbox::SimpleGet(result, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, headers)) - { - lua_pushlstring(state, result.c_str(), result.size()); - return 1; - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: " << e.What(); - } - - LOG(ERROR) << "Lua: Error in RestApiGet() for URI: " << uri; - lua_pushnil(state); - return 1; - } - - - int LuaScripting::RestApiPostOrPut(lua_State *state, - bool isPost) - { - ServerContext* serverContext = GetServerContext(state); - if (serverContext == NULL) - { - LOG(ERROR) << "Lua: The Orthanc API is unavailable"; - lua_pushnil(state); - return 1; - } - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if (nArgs < 2 || nArgs > 4 || - !lua_isstring(state, 1) || // URI - !lua_isstring(state, 2) || // Body - (nArgs >= 3 && !lua_isboolean(state, 3))) // Restrict to built-in API? - { - LOG(ERROR) << "Lua: Bad parameters to " << (isPost ? "RestApiPost()" : "RestApiPut()"); - lua_pushnil(state); - return 1; - } - - const char* uri = lua_tostring(state, 1); - size_t bodySize = 0; - const char* bodyData = lua_tolstring(state, 2, &bodySize); - bool builtin = (nArgs == 3 ? lua_toboolean(state, 3) != 0 : false); - - std::map headers; - LuaContext::GetDictionaryArgument(headers, state, 4, true /* HTTP header key to lower case */); - - try - { - std::string result; - if (isPost ? - HttpToolbox::SimplePost(result, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, bodyData, bodySize, headers) : - HttpToolbox::SimplePut(result, serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, bodyData, bodySize, headers)) - { - lua_pushlstring(state, result.c_str(), result.size()); - return 1; - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: " << e.What(); - } - - LOG(ERROR) << "Lua: Error in " << (isPost ? "RestApiPost()" : "RestApiPut()") << " for URI: " << uri; - lua_pushnil(state); - return 1; - } - - - // Syntax in Lua: RestApiPost(uri, body, builtin) - int LuaScripting::RestApiPost(lua_State *state) - { - return RestApiPostOrPut(state, true); - } - - - // Syntax in Lua: RestApiPut(uri, body, builtin) - int LuaScripting::RestApiPut(lua_State *state) - { - return RestApiPostOrPut(state, false); - } - - - // Syntax in Lua: RestApiDelete(uri, builtin) - int LuaScripting::RestApiDelete(lua_State *state) - { - ServerContext* serverContext = GetServerContext(state); - if (serverContext == NULL) - { - LOG(ERROR) << "Lua: The Orthanc API is unavailable"; - lua_pushnil(state); - return 1; - } - - // Check the types of the arguments - int nArgs = lua_gettop(state); - if (nArgs < 1 || nArgs > 3 || - !lua_isstring(state, 1) || // URI - (nArgs >= 2 && !lua_isboolean(state, 2))) // Restrict to built-in API? - { - LOG(ERROR) << "Lua: Bad parameters to RestApiDelete()"; - lua_pushnil(state); - return 1; - } - - const char* uri = lua_tostring(state, 1); - bool builtin = (nArgs == 2 ? lua_toboolean(state, 2) != 0 : false); - - std::map headers; - LuaContext::GetDictionaryArgument(headers, state, 3, true /* HTTP header key to lower case */); - - try - { - if (HttpToolbox::SimpleDelete(serverContext->GetHttpHandler().RestrictToOrthancRestApi(builtin), - RequestOrigin_Lua, uri, headers)) - { - lua_pushboolean(state, 1); - return 1; - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: " << e.What(); - } - - LOG(ERROR) << "Lua: Error in RestApiDelete() for URI: " << uri; - lua_pushnil(state); - - return 1; - } - - - // Syntax in Lua: GetOrthancConfiguration() - int LuaScripting::GetOrthancConfiguration(lua_State *state) - { - Json::Value configuration; - - { - OrthancConfiguration::ReaderLock lock; - configuration = lock.GetJson(); - } - - LuaContext::GetLuaContext(state).PushJson(configuration); - - return 1; - } - - - size_t LuaScripting::ParseOperation(LuaJobManager::Lock& lock, - const std::string& operation, - const Json::Value& parameters) - { - if (operation == "delete") - { - LOG(INFO) << "Lua script to delete resource " << parameters["Resource"].asString(); - return lock.AddDeleteResourceOperation(context_); - } - - if (operation == "store-scu") - { - std::string localAet; - if (parameters.isMember("LocalAet")) - { - localAet = parameters["LocalAet"].asString(); - } - else - { - localAet = context_.GetDefaultLocalApplicationEntityTitle(); - } - - std::string name = parameters["Modality"].asString(); - RemoteModalityParameters modality; - - { - OrthancConfiguration::ReaderLock configLock; - modality = configLock.GetConfiguration().GetModalityUsingSymbolicName(name); - } - - // This is not a C-MOVE: No need to call "StoreScuCommand::SetMoveOriginator()" - return lock.AddStoreScuOperation(context_, localAet, modality); - } - - if (operation == "store-peer") - { - OrthancConfiguration::ReaderLock configLock; - std::string name = parameters["Peer"].asString(); - - WebServiceParameters peer; - if (configLock.GetConfiguration().LookupOrthancPeer(peer, name)) - { - return lock.AddStorePeerOperation(peer); - } - else - { - throw OrthancException(ErrorCode_UnknownResource, - "No peer with symbolic name: " + name); - } - } - - if (operation == "modify") - { - std::unique_ptr modification(new DicomModification); - modification->ParseModifyRequest(parameters); - - return lock.AddModifyInstanceOperation(context_, modification.release()); - } - - if (operation == "call-system") - { - LOG(INFO) << "Lua script to call system command on " << parameters["Resource"].asString(); - - const Json::Value& argsIn = parameters["Arguments"]; - if (argsIn.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - std::vector args; - args.reserve(argsIn.size()); - for (Json::Value::ArrayIndex i = 0; i < argsIn.size(); ++i) - { - // http://jsoncpp.sourceforge.net/namespace_json.html#7d654b75c16a57007925868e38212b4e - switch (argsIn[i].type()) - { - case Json::stringValue: - args.push_back(argsIn[i].asString()); - break; - - case Json::intValue: - args.push_back(boost::lexical_cast(argsIn[i].asInt())); - break; - - case Json::uintValue: - args.push_back(boost::lexical_cast(argsIn[i].asUInt())); - break; - - case Json::realValue: - args.push_back(boost::lexical_cast(argsIn[i].asFloat())); - break; - - default: - throw OrthancException(ErrorCode_BadParameterType); - } - } - - std::string command = parameters["Command"].asString(); - std::vector postArgs; - - return lock.AddSystemCallOperation(command, args, postArgs); - } - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - - void LuaScripting::InitializeJob() - { - lua_.Execute("_InitializeJob()"); - } - - - void LuaScripting::SubmitJob() - { - Json::Value operations; - LuaFunctionCall call2(lua_, "_AccessJob"); - call2.ExecuteToJson(operations, false); - - if (operations.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_InternalError); - } - - LuaJobManager::Lock lock(jobManager_, context_.GetJobsEngine()); - - bool isFirst = true; - size_t previous = 0; // Dummy initialization to avoid warning - - for (Json::Value::ArrayIndex i = 0; i < operations.size(); ++i) - { - if (operations[i].type() != Json::objectValue || - !operations[i].isMember("Operation")) - { - throw OrthancException(ErrorCode_InternalError); - } - - const Json::Value& parameters = operations[i]; - if (!parameters.isMember("Resource")) - { - throw OrthancException(ErrorCode_InternalError); - } - - std::string operation = parameters["Operation"].asString(); - size_t index = ParseOperation(lock, operation, operations[i]); - - std::string resource = parameters["Resource"].asString(); - if (!resource.empty()) - { - lock.AddDicomInstanceInput(index, context_, resource); - } - else if (!isFirst) - { - lock.Connect(previous, index); - } - - isFirst = false; - previous = index; - } - } - - - LuaScripting::LuaScripting(ServerContext& context) : - context_(context), - state_(State_Setup) - { - lua_.SetGlobalVariable("_ServerContext", &context); - lua_.RegisterFunction("RestApiGet", RestApiGet); - lua_.RegisterFunction("RestApiPost", RestApiPost); - lua_.RegisterFunction("RestApiPut", RestApiPut); - lua_.RegisterFunction("RestApiDelete", RestApiDelete); - lua_.RegisterFunction("GetOrthancConfiguration", GetOrthancConfiguration); - - LOG(INFO) << "Initializing Lua for the event handler"; - LoadGlobalConfiguration(); - } - - - LuaScripting::~LuaScripting() - { - if (state_ == State_Running) - { - LOG(ERROR) << "INTERNAL ERROR: LuaScripting::Stop() should be invoked manually to avoid mess in the destruction order!"; - Stop(); - } - } - - - void LuaScripting::EventThread(LuaScripting* that) - { - for (;;) - { - std::unique_ptr event(that->pendingEvents_.Dequeue(100)); - - if (event.get() == NULL) - { - // The event queue is empty, check whether we should stop - boost::recursive_mutex::scoped_lock lock(that->mutex_); - - if (that->state_ != State_Running) - { - return; - } - } - else - { - try - { - dynamic_cast(*event).Apply(*that); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Error while processing Lua events: " << e.What(); - } - } - - that->jobManager_.GetDicomConnectionManager().CloseIfInactive(); - } - } - - - void LuaScripting::Start() - { - boost::recursive_mutex::scoped_lock lock(mutex_); - - if (state_ != State_Setup || - eventThread_.joinable() /* already started */) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - LOG(INFO) << "Starting the Lua engine"; - eventThread_ = boost::thread(EventThread, this); - state_ = State_Running; - } - } - - - void LuaScripting::Stop() - { - { - boost::recursive_mutex::scoped_lock lock(mutex_); - - if (state_ != State_Running) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - state_ = State_Done; - } - - jobManager_.AwakeTrailingSleep(); - - if (eventThread_.joinable()) - { - LOG(INFO) << "Stopping the Lua engine"; - eventThread_.join(); - LOG(INFO) << "The Lua engine has stopped"; - } - } - - - void LuaScripting::SignalStoredInstance(const std::string& publicId, - const DicomInstanceToStore& instance, - const Json::Value& simplifiedTags) - { - Json::Value metadata = Json::objectValue; - - for (ServerIndex::MetadataMap::const_iterator - it = instance.GetMetadata().begin(); - it != instance.GetMetadata().end(); ++it) - { - if (it->first.first == ResourceType_Instance) - { - metadata[EnumerationToString(it->first.second)] = it->second; - } - } - - pendingEvents_.Enqueue(new OnStoredInstanceEvent(publicId, simplifiedTags, metadata, instance)); - } - - - void LuaScripting::SignalChange(const ServerIndexChange& change) - { - if (change.GetChangeType() == ChangeType_StablePatient || - change.GetChangeType() == ChangeType_StableStudy || - change.GetChangeType() == ChangeType_StableSeries) - { - pendingEvents_.Enqueue(new StableResourceEvent(change)); - } - else if (change.GetChangeType() == ChangeType_Deleted) - { - pendingEvents_.Enqueue(new DeleteEvent(change.GetResourceType(), change.GetPublicId())); - } - else if (change.GetChangeType() == ChangeType_UpdatedAttachment || - change.GetChangeType() == ChangeType_UpdatedMetadata) - { - pendingEvents_.Enqueue(new UpdateEvent(change.GetResourceType(), change.GetPublicId())); - } - } - - - bool LuaScripting::FilterIncomingInstance(const DicomInstanceToStore& instance, - const Json::Value& simplified) - { - static const char* NAME = "ReceivedInstanceFilter"; - - boost::recursive_mutex::scoped_lock lock(mutex_); - - if (lua_.IsExistingFunction(NAME)) - { - LuaFunctionCall call(lua_, NAME); - call.PushJson(simplified); - - Json::Value origin; - instance.GetOrigin().Format(origin); - call.PushJson(origin); - - Json::Value info = Json::objectValue; - info["HasPixelData"] = instance.HasPixelData(); - - std::string s; - if (instance.LookupTransferSyntax(s)) - { - info["TransferSyntaxUID"] = s; - } - - call.PushJson(info); - - if (!call.ExecutePredicate()) - { - return false; - } - } - - return true; - } - - - void LuaScripting::Execute(const std::string& command) - { - pendingEvents_.Enqueue(new ExecuteEvent(command)); - } - - - void LuaScripting::LoadGlobalConfiguration() - { - OrthancConfiguration::ReaderLock configLock; - - lua_.Execute(Orthanc::EmbeddedResources::LUA_TOOLBOX); - - std::list luaScripts; - configLock.GetConfiguration().GetListOfStringsParameter(luaScripts, "LuaScripts"); - - LuaScripting::Lock lock(*this); - - for (std::list::const_iterator - it = luaScripts.begin(); it != luaScripts.end(); ++it) - { - std::string path = configLock.GetConfiguration().InterpretStringParameterAsPath(*it); - LOG(INFO) << "Installing the Lua scripts from: " << path; - std::string script; - SystemToolbox::ReadFile(script, path); - - lock.GetLua().Execute(script); - } - } - - - void LuaScripting::SignalJobSubmitted(const std::string& jobId) - { - pendingEvents_.Enqueue(new JobEvent(JobEvent::Type_Submitted, jobId)); - } - - - void LuaScripting::SignalJobSuccess(const std::string& jobId) - { - pendingEvents_.Enqueue(new JobEvent(JobEvent::Type_Success, jobId)); - } - - - void LuaScripting::SignalJobFailure(const std::string& jobId) - { - pendingEvents_.Enqueue(new JobEvent(JobEvent::Type_Failure, jobId)); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/LuaScripting.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomInstanceToStore.h" -#include "ServerIndexChange.h" -#include "ServerJobs/LuaJobManager.h" - -#include "../Core/MultiThreading/SharedMessageQueue.h" -#include "../Core/Lua/LuaContext.h" - -namespace Orthanc -{ - class ServerContext; - - class LuaScripting : public boost::noncopyable - { - private: - enum State - { - State_Setup, - State_Running, - State_Done - }; - - class ExecuteEvent; - class IEvent; - class OnStoredInstanceEvent; - class StableResourceEvent; - class JobEvent; - class DeleteEvent; - class UpdateEvent; - - static ServerContext* GetServerContext(lua_State *state); - - static int RestApiPostOrPut(lua_State *state, - bool isPost); - static int RestApiGet(lua_State *state); - static int RestApiPost(lua_State *state); - static int RestApiPut(lua_State *state); - static int RestApiDelete(lua_State *state); - static int GetOrthancConfiguration(lua_State *state); - - size_t ParseOperation(LuaJobManager::Lock& lock, - const std::string& operation, - const Json::Value& parameters); - - void InitializeJob(); - - void SubmitJob(); - - boost::recursive_mutex mutex_; - LuaContext lua_; - ServerContext& context_; - LuaJobManager jobManager_; - State state_; - boost::thread eventThread_; - SharedMessageQueue pendingEvents_; - - static void EventThread(LuaScripting* that); - - void LoadGlobalConfiguration(); - - public: - class Lock : public boost::noncopyable - { - private: - LuaScripting& that_; - boost::recursive_mutex::scoped_lock lock_; - - public: - explicit Lock(LuaScripting& that) : - that_(that), - lock_(that.mutex_) - { - } - - LuaContext& GetLua() - { - return that_.lua_; - } - }; - - LuaScripting(ServerContext& context); - - ~LuaScripting(); - - void Start(); - - void Stop(); - - void SignalStoredInstance(const std::string& publicId, - const DicomInstanceToStore& instance, - const Json::Value& simplifiedTags); - - void SignalChange(const ServerIndexChange& change); - - bool FilterIncomingInstance(const DicomInstanceToStore& instance, - const Json::Value& simplifiedTags); - - void Execute(const std::string& command); - - void SignalJobSubmitted(const std::string& jobId); - - void SignalJobSuccess(const std::string& jobId); - - void SignalJobFailure(const std::string& jobId); - - TimeoutDicomConnectionManager& GetDicomConnectionManager() - { - return jobManager_.GetDicomConnectionManager(); - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/main.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/main.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/main.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/main.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1689 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "OrthancRestApi/OrthancRestApi.h" - -#include - -#include "../Core/Compatibility.h" -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/DicomNetworking/DicomAssociationParameters.h" -#include "../Core/DicomNetworking/DicomServer.h" -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/HttpServer/EmbeddedResourceHttpHandler.h" -#include "../Core/HttpServer/FilesystemHttpHandler.h" -#include "../Core/HttpServer/HttpServer.h" -#include "../Core/Logging.h" -#include "../Core/Lua/LuaFunctionCall.h" -#include "../Plugins/Engine/OrthancPlugins.h" -#include "OrthancConfiguration.h" -#include "OrthancFindRequestHandler.h" -#include "OrthancInitialization.h" -#include "OrthancMoveRequestHandler.h" -#include "OrthancGetRequestHandler.h" -#include "ServerContext.h" -#include "ServerJobs/StorageCommitmentScpJob.h" -#include "ServerToolbox.h" -#include "StorageCommitmentReports.h" - -using namespace Orthanc; - - -class OrthancStoreRequestHandler : public IStoreRequestHandler -{ -private: - ServerContext& context_; - -public: - OrthancStoreRequestHandler(ServerContext& context) : - context_(context) - { - } - - - virtual void Handle(const std::string& dicomFile, - const DicomMap& dicomSummary, - const Json::Value& dicomJson, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) - { - if (dicomFile.size() > 0) - { - DicomInstanceToStore toStore; - toStore.SetOrigin(DicomInstanceOrigin::FromDicomProtocol - (remoteIp.c_str(), remoteAet.c_str(), calledAet.c_str())); - toStore.SetBuffer(dicomFile.c_str(), dicomFile.size()); - toStore.SetSummary(dicomSummary); - toStore.SetJson(dicomJson); - - std::string id; - context_.Store(id, toStore, StoreInstanceMode_Default); - } - } -}; - - - -class OrthancStorageCommitmentRequestHandler : public IStorageCommitmentRequestHandler -{ -private: - ServerContext& context_; - -public: - OrthancStorageCommitmentRequestHandler(ServerContext& context) : - context_(context) - { - } - - virtual void HandleRequest(const std::string& transactionUid, - const std::vector& referencedSopClassUids, - const std::vector& referencedSopInstanceUids, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) - { - if (referencedSopClassUids.size() != referencedSopInstanceUids.size()) - { - throw OrthancException(ErrorCode_InternalError); - } - - std::unique_ptr job( - new StorageCommitmentScpJob(context_, transactionUid, remoteAet, calledAet)); - - for (size_t i = 0; i < referencedSopClassUids.size(); i++) - { - job->AddInstance(referencedSopClassUids[i], referencedSopInstanceUids[i]); - } - - job->MarkAsReady(); - - context_.GetJobsEngine().GetRegistry().Submit(job.release(), 0 /* default priority */); - } - - virtual void HandleReport(const std::string& transactionUid, - const std::vector& successSopClassUids, - const std::vector& successSopInstanceUids, - const std::vector& failedSopClassUids, - const std::vector& failedSopInstanceUids, - const std::vector& failureReasons, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) - { - if (successSopClassUids.size() != successSopInstanceUids.size() || - failedSopClassUids.size() != failedSopInstanceUids.size() || - failedSopClassUids.size() != failureReasons.size()) - { - throw OrthancException(ErrorCode_InternalError); - } - - std::unique_ptr report( - new StorageCommitmentReports::Report(remoteAet)); - - for (size_t i = 0; i < successSopClassUids.size(); i++) - { - report->AddSuccess(successSopClassUids[i], successSopInstanceUids[i]); - } - - for (size_t i = 0; i < failedSopClassUids.size(); i++) - { - report->AddFailure(failedSopClassUids[i], failedSopInstanceUids[i], failureReasons[i]); - } - - report->MarkAsComplete(); - - context_.GetStorageCommitmentReports().Store(transactionUid, report.release()); - } -}; - - - -class ModalitiesFromConfiguration : public DicomServer::IRemoteModalities -{ -public: - virtual bool IsSameAETitle(const std::string& aet1, - const std::string& aet2) - { - OrthancConfiguration::ReaderLock lock; - return lock.GetConfiguration().IsSameAETitle(aet1, aet2); - } - - virtual bool LookupAETitle(RemoteModalityParameters& modality, - const std::string& aet) - { - OrthancConfiguration::ReaderLock lock; - return lock.GetConfiguration().LookupDicomModalityUsingAETitle(modality, aet); - } -}; - - -class MyDicomServerFactory : - public IStoreRequestHandlerFactory, - public IFindRequestHandlerFactory, - public IMoveRequestHandlerFactory, - public IGetRequestHandlerFactory, - public IStorageCommitmentRequestHandlerFactory -{ -private: - ServerContext& context_; - -public: - MyDicomServerFactory(ServerContext& context) : context_(context) - { - } - - virtual IStoreRequestHandler* ConstructStoreRequestHandler() - { - return new OrthancStoreRequestHandler(context_); - } - - virtual IFindRequestHandler* ConstructFindRequestHandler() - { - std::unique_ptr result(new OrthancFindRequestHandler(context_)); - - { - OrthancConfiguration::ReaderLock lock; - result->SetMaxResults(lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindResults", 0)); - result->SetMaxInstances(lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindInstances", 0)); - } - - if (result->GetMaxResults() == 0) - { - LOG(INFO) << "No limit on the number of C-FIND results at the Patient, Study and Series levels"; - } - else - { - LOG(INFO) << "Maximum " << result->GetMaxResults() - << " results for C-FIND queries at the Patient, Study and Series levels"; - } - - if (result->GetMaxInstances() == 0) - { - LOG(INFO) << "No limit on the number of C-FIND results at the Instance level"; - } - else - { - LOG(INFO) << "Maximum " << result->GetMaxInstances() - << " instances will be returned for C-FIND queries at the Instance level"; - } - - return result.release(); - } - - virtual IMoveRequestHandler* ConstructMoveRequestHandler() - { - return new OrthancMoveRequestHandler(context_); - } - - virtual IGetRequestHandler* ConstructGetRequestHandler() - { - return new OrthancGetRequestHandler(context_); - } - - virtual IStorageCommitmentRequestHandler* ConstructStorageCommitmentRequestHandler() - { - return new OrthancStorageCommitmentRequestHandler(context_); - } - - - void Done() - { - } -}; - - -class OrthancApplicationEntityFilter : public IApplicationEntityFilter -{ -private: - ServerContext& context_; - bool alwaysAllowEcho_; - bool alwaysAllowStore_; - -public: - OrthancApplicationEntityFilter(ServerContext& context) : - context_(context) - { - OrthancConfiguration::ReaderLock lock; - alwaysAllowEcho_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowEcho", true); - alwaysAllowStore_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowStore", true); - } - - virtual bool IsAllowedConnection(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) - { - LOG(INFO) << "Incoming connection from AET " << remoteAet - << " on IP " << remoteIp << ", calling AET " << calledAet; - - if (alwaysAllowEcho_ || - alwaysAllowStore_) - { - return true; - } - else - { - OrthancConfiguration::ReaderLock lock; - return lock.GetConfiguration().IsKnownAETitle(remoteAet, remoteIp); - } - } - - virtual bool IsAllowedRequest(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - DicomRequestType type) - { - LOG(INFO) << "Incoming " << EnumerationToString(type) << " request from AET " - << remoteAet << " on IP " << remoteIp << ", calling AET " << calledAet; - - if (type == DicomRequestType_Echo && - alwaysAllowEcho_) - { - // Incoming C-Echo requests are always accepted, even from unknown AET - return true; - } - else if (type == DicomRequestType_Store && - alwaysAllowStore_) - { - // Incoming C-Store requests are always accepted, even from unknown AET - return true; - } - else - { - OrthancConfiguration::ReaderLock lock; - - RemoteModalityParameters modality; - if (lock.GetConfiguration().LookupDicomModalityUsingAETitle(modality, remoteAet)) - { - return modality.IsRequestAllowed(type); - } - else - { - return false; - } - } - } - - virtual bool IsAllowedTransferSyntax(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - TransferSyntax syntax) - { - std::string configuration; - - switch (syntax) - { - case TransferSyntax_Deflated: - configuration = "DeflatedTransferSyntaxAccepted"; - break; - - case TransferSyntax_Jpeg: - configuration = "JpegTransferSyntaxAccepted"; - break; - - case TransferSyntax_Jpeg2000: - configuration = "Jpeg2000TransferSyntaxAccepted"; - break; - - case TransferSyntax_JpegLossless: - configuration = "JpegLosslessTransferSyntaxAccepted"; - break; - - case TransferSyntax_Jpip: - configuration = "JpipTransferSyntaxAccepted"; - break; - - case TransferSyntax_Mpeg2: - configuration = "Mpeg2TransferSyntaxAccepted"; - break; - - case TransferSyntax_Mpeg4: - configuration = "Mpeg4TransferSyntaxAccepted"; - break; - - case TransferSyntax_Rle: - configuration = "RleTransferSyntaxAccepted"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - { - std::string name = "Is" + configuration; - - LuaScripting::Lock lock(context_.GetLuaScripting()); - - if (lock.GetLua().IsExistingFunction(name.c_str())) - { - LuaFunctionCall call(lock.GetLua(), name.c_str()); - call.PushString(remoteAet); - call.PushString(remoteIp); - call.PushString(calledAet); - return call.ExecutePredicate(); - } - } - - { - OrthancConfiguration::ReaderLock lock; - return lock.GetConfiguration().GetBooleanParameter(configuration, true); - } - } - - - virtual bool IsUnknownSopClassAccepted(const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet) - { - static const char* configuration = "UnknownSopClassAccepted"; - - { - std::string lua = "Is" + std::string(configuration); - - LuaScripting::Lock lock(context_.GetLuaScripting()); - - if (lock.GetLua().IsExistingFunction(lua.c_str())) - { - LuaFunctionCall call(lock.GetLua(), lua.c_str()); - call.PushString(remoteAet); - call.PushString(remoteIp); - call.PushString(calledAet); - return call.ExecutePredicate(); - } - } - - { - OrthancConfiguration::ReaderLock lock; - return lock.GetConfiguration().GetBooleanParameter(configuration, false); - } - } -}; - - -class MyIncomingHttpRequestFilter : public IIncomingHttpRequestFilter -{ -private: - ServerContext& context_; - OrthancPlugins* plugins_; - -public: - MyIncomingHttpRequestFilter(ServerContext& context, - OrthancPlugins* plugins) : - context_(context), - plugins_(plugins) - { - } - - virtual bool IsAllowed(HttpMethod method, - const char* uri, - const char* ip, - const char* username, - const IHttpHandler::Arguments& httpHeaders, - const IHttpHandler::GetArguments& getArguments) - { -#if ORTHANC_ENABLE_PLUGINS == 1 - if (plugins_ != NULL && - !plugins_->IsAllowed(method, uri, ip, username, httpHeaders, getArguments)) - { - return false; - } -#endif - - static const char* HTTP_FILTER = "IncomingHttpRequestFilter"; - - LuaScripting::Lock lock(context_.GetLuaScripting()); - - // Test if the instance must be filtered out - if (lock.GetLua().IsExistingFunction(HTTP_FILTER)) - { - LuaFunctionCall call(lock.GetLua(), HTTP_FILTER); - - switch (method) - { - case HttpMethod_Get: - call.PushString("GET"); - break; - - case HttpMethod_Put: - call.PushString("PUT"); - break; - - case HttpMethod_Post: - call.PushString("POST"); - break; - - case HttpMethod_Delete: - call.PushString("DELETE"); - break; - - default: - return true; - } - - call.PushString(uri); - call.PushString(ip); - call.PushString(username); - call.PushStringMap(httpHeaders); - - if (!call.ExecutePredicate()) - { - LOG(INFO) << "An incoming HTTP request has been discarded by the filter"; - return false; - } - } - - return true; - } -}; - - - -class MyHttpExceptionFormatter : public IHttpExceptionFormatter -{ -private: - bool describeErrors_; - OrthancPlugins* plugins_; - -public: - MyHttpExceptionFormatter(bool describeErrors, - OrthancPlugins* plugins) : - describeErrors_(describeErrors), - plugins_(plugins) - { - } - - virtual void Format(HttpOutput& output, - const OrthancException& exception, - HttpMethod method, - const char* uri) - { - { - bool isPlugin = false; - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (plugins_ != NULL) - { - plugins_->GetErrorDictionary().LogError(exception.GetErrorCode(), true); - isPlugin = true; - } -#endif - - if (!isPlugin) - { - LOG(ERROR) << "Exception in the HTTP handler: " << exception.What(); - } - } - - Json::Value message = Json::objectValue; - ErrorCode errorCode = exception.GetErrorCode(); - HttpStatus httpStatus = exception.GetHttpStatus(); - - { - bool isPlugin = false; - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (plugins_ != NULL && - plugins_->GetErrorDictionary().Format(message, httpStatus, exception)) - { - errorCode = ErrorCode_Plugin; - isPlugin = true; - } -#endif - - if (!isPlugin) - { - message["Message"] = exception.What(); - } - } - - if (!describeErrors_) - { - output.SendStatus(httpStatus); - } - else - { - message["Method"] = EnumerationToString(method); - message["Uri"] = uri; - message["HttpError"] = EnumerationToString(httpStatus); - message["HttpStatus"] = httpStatus; - message["OrthancError"] = EnumerationToString(errorCode); - message["OrthancStatus"] = errorCode; - - if (exception.HasDetails()) - { - message["Details"] = exception.GetDetails(); - } - - std::string info = message.toStyledString(); - output.SendStatus(httpStatus, info); - } - } -}; - - - -static void PrintHelp(const char* path) -{ - std::cout - << "Usage: " << path << " [OPTION]... [CONFIGURATION]" << std::endl - << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." << std::endl - << std::endl - << "The \"CONFIGURATION\" argument can be a single file or a directory. In the " << std::endl - << "case of a directory, all the JSON files it contains will be merged. " << std::endl - << "If no configuration path is given on the command line, a set of default " << std::endl - << "parameters is used. Please refer to the Orthanc homepage for the full " << std::endl - << "instructions about how to use Orthanc ." << std::endl - << std::endl - << "Command-line options:" << std::endl - << " --help\t\tdisplay this help and exit" << std::endl - << " --logdir=[dir]\tdirectory where to store the log files" << std::endl - << "\t\t\t(by default, the log is dumped to stderr)" << std::endl - << " --logfile=[file]\tfile where to store the log of Orthanc" << std::endl - << "\t\t\t(by default, the log is dumped to stderr)" << std::endl - << " --config=[file]\tcreate a sample configuration file and exit" << std::endl - << "\t\t\t(if file is \"-\", dumps to stdout)" << std::endl - << " --errors\t\tprint the supported error codes and exit" << std::endl - << " --verbose\t\tbe verbose in logs" << std::endl - << " --trace\t\thighest verbosity in logs (for debug)" << std::endl - << " --upgrade\t\tallow Orthanc to upgrade the version of the" << std::endl - << "\t\t\tdatabase (beware that the database will become" << std::endl - << "\t\t\tincompatible with former versions of Orthanc)" << std::endl - << " --no-jobs\t\tDon't restart the jobs that were stored during" << std::endl - << "\t\t\tthe last execution of Orthanc" << std::endl - << " --version\t\toutput version information and exit" << std::endl - << std::endl - << "Exit status:" << std::endl - << " 0 if success," << std::endl -#if defined(_WIN32) - << "!= 0 if error (use the --errors option to get the list of possible errors)." << std::endl -#else - << " -1 if error (have a look at the logs)." << std::endl -#endif - << std::endl; -} - - -static void PrintVersion(const char* path) -{ - std::cout - << path << " " << ORTHANC_VERSION << std::endl - << "Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics Department, University Hospital of Liege (Belgium)" << std::endl - << "Copyright (C) 2017-2020 Osimis S.A. (Belgium)" << std::endl - << "Licensing GPLv3+: GNU GPL version 3 or later , with OpenSSL exception." << std::endl - << "This is free software: you are free to change and redistribute it." << std::endl - << "There is NO WARRANTY, to the extent permitted by law." << std::endl - << std::endl - << "Written by Sebastien Jodogne " << std::endl; -} - - -static void PrintErrorCode(ErrorCode code, const char* description) -{ - std::cout - << std::right << std::setw(16) - << static_cast(code) - << " " << description << std::endl; -} - - -static void PrintErrors(const char* path) -{ - std::cout - << path << " " << ORTHANC_VERSION << std::endl - << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." - << std::endl << std::endl - << "List of error codes that could be returned by Orthanc:" - << std::endl << std::endl; - - // The content of the following brackets is automatically generated - // by the "GenerateErrorCodes.py" script - { - PrintErrorCode(ErrorCode_InternalError, "Internal error"); - PrintErrorCode(ErrorCode_Success, "Success"); - PrintErrorCode(ErrorCode_Plugin, "Error encountered within the plugin engine"); - PrintErrorCode(ErrorCode_NotImplemented, "Not implemented yet"); - PrintErrorCode(ErrorCode_ParameterOutOfRange, "Parameter out of range"); - PrintErrorCode(ErrorCode_NotEnoughMemory, "The server hosting Orthanc is running out of memory"); - PrintErrorCode(ErrorCode_BadParameterType, "Bad type for a parameter"); - PrintErrorCode(ErrorCode_BadSequenceOfCalls, "Bad sequence of calls"); - PrintErrorCode(ErrorCode_InexistentItem, "Accessing an inexistent item"); - PrintErrorCode(ErrorCode_BadRequest, "Bad request"); - PrintErrorCode(ErrorCode_NetworkProtocol, "Error in the network protocol"); - PrintErrorCode(ErrorCode_SystemCommand, "Error while calling a system command"); - PrintErrorCode(ErrorCode_Database, "Error with the database engine"); - PrintErrorCode(ErrorCode_UriSyntax, "Badly formatted URI"); - PrintErrorCode(ErrorCode_InexistentFile, "Inexistent file"); - PrintErrorCode(ErrorCode_CannotWriteFile, "Cannot write to file"); - PrintErrorCode(ErrorCode_BadFileFormat, "Bad file format"); - PrintErrorCode(ErrorCode_Timeout, "Timeout"); - PrintErrorCode(ErrorCode_UnknownResource, "Unknown resource"); - PrintErrorCode(ErrorCode_IncompatibleDatabaseVersion, "Incompatible version of the database"); - PrintErrorCode(ErrorCode_FullStorage, "The file storage is full"); - PrintErrorCode(ErrorCode_CorruptedFile, "Corrupted file (e.g. inconsistent MD5 hash)"); - PrintErrorCode(ErrorCode_InexistentTag, "Inexistent tag"); - PrintErrorCode(ErrorCode_ReadOnly, "Cannot modify a read-only data structure"); - PrintErrorCode(ErrorCode_IncompatibleImageFormat, "Incompatible format of the images"); - PrintErrorCode(ErrorCode_IncompatibleImageSize, "Incompatible size of the images"); - PrintErrorCode(ErrorCode_SharedLibrary, "Error while using a shared library (plugin)"); - PrintErrorCode(ErrorCode_UnknownPluginService, "Plugin invoking an unknown service"); - PrintErrorCode(ErrorCode_UnknownDicomTag, "Unknown DICOM tag"); - PrintErrorCode(ErrorCode_BadJson, "Cannot parse a JSON document"); - PrintErrorCode(ErrorCode_Unauthorized, "Bad credentials were provided to an HTTP request"); - PrintErrorCode(ErrorCode_BadFont, "Badly formatted font file"); - PrintErrorCode(ErrorCode_DatabasePlugin, "The plugin implementing a custom database back-end does not fulfill the proper interface"); - PrintErrorCode(ErrorCode_StorageAreaPlugin, "Error in the plugin implementing a custom storage area"); - PrintErrorCode(ErrorCode_EmptyRequest, "The request is empty"); - PrintErrorCode(ErrorCode_NotAcceptable, "Cannot send a response which is acceptable according to the Accept HTTP header"); - PrintErrorCode(ErrorCode_NullPointer, "Cannot handle a NULL pointer"); - PrintErrorCode(ErrorCode_DatabaseUnavailable, "The database is currently not available (probably a transient situation)"); - PrintErrorCode(ErrorCode_CanceledJob, "This job was canceled"); - PrintErrorCode(ErrorCode_BadGeometry, "Geometry error encountered in Stone"); - PrintErrorCode(ErrorCode_SslInitialization, "Cannot initialize SSL encryption, check out your certificates"); - PrintErrorCode(ErrorCode_SQLiteNotOpened, "SQLite: The database is not opened"); - PrintErrorCode(ErrorCode_SQLiteAlreadyOpened, "SQLite: Connection is already open"); - PrintErrorCode(ErrorCode_SQLiteCannotOpen, "SQLite: Unable to open the database"); - PrintErrorCode(ErrorCode_SQLiteStatementAlreadyUsed, "SQLite: This cached statement is already being referred to"); - PrintErrorCode(ErrorCode_SQLiteExecute, "SQLite: Cannot execute a command"); - PrintErrorCode(ErrorCode_SQLiteRollbackWithoutTransaction, "SQLite: Rolling back a nonexistent transaction (have you called Begin()?)"); - PrintErrorCode(ErrorCode_SQLiteCommitWithoutTransaction, "SQLite: Committing a nonexistent transaction"); - PrintErrorCode(ErrorCode_SQLiteRegisterFunction, "SQLite: Unable to register a function"); - PrintErrorCode(ErrorCode_SQLiteFlush, "SQLite: Unable to flush the database"); - PrintErrorCode(ErrorCode_SQLiteCannotRun, "SQLite: Cannot run a cached statement"); - PrintErrorCode(ErrorCode_SQLiteCannotStep, "SQLite: Cannot step over a cached statement"); - PrintErrorCode(ErrorCode_SQLiteBindOutOfRange, "SQLite: Bing a value while out of range (serious error)"); - PrintErrorCode(ErrorCode_SQLitePrepareStatement, "SQLite: Cannot prepare a cached statement"); - PrintErrorCode(ErrorCode_SQLiteTransactionAlreadyStarted, "SQLite: Beginning the same transaction twice"); - PrintErrorCode(ErrorCode_SQLiteTransactionCommit, "SQLite: Failure when committing the transaction"); - PrintErrorCode(ErrorCode_SQLiteTransactionBegin, "SQLite: Cannot start a transaction"); - PrintErrorCode(ErrorCode_DirectoryOverFile, "The directory to be created is already occupied by a regular file"); - PrintErrorCode(ErrorCode_FileStorageCannotWrite, "Unable to create a subdirectory or a file in the file storage"); - PrintErrorCode(ErrorCode_DirectoryExpected, "The specified path does not point to a directory"); - PrintErrorCode(ErrorCode_HttpPortInUse, "The TCP port of the HTTP server is privileged or already in use"); - PrintErrorCode(ErrorCode_DicomPortInUse, "The TCP port of the DICOM server is privileged or already in use"); - PrintErrorCode(ErrorCode_BadHttpStatusInRest, "This HTTP status is not allowed in a REST API"); - PrintErrorCode(ErrorCode_RegularFileExpected, "The specified path does not point to a regular file"); - PrintErrorCode(ErrorCode_PathToExecutable, "Unable to get the path to the executable"); - PrintErrorCode(ErrorCode_MakeDirectory, "Cannot create a directory"); - PrintErrorCode(ErrorCode_BadApplicationEntityTitle, "An application entity title (AET) cannot be empty or be longer than 16 characters"); - PrintErrorCode(ErrorCode_NoCFindHandler, "No request handler factory for DICOM C-FIND SCP"); - PrintErrorCode(ErrorCode_NoCMoveHandler, "No request handler factory for DICOM C-MOVE SCP"); - PrintErrorCode(ErrorCode_NoCStoreHandler, "No request handler factory for DICOM C-STORE SCP"); - PrintErrorCode(ErrorCode_NoApplicationEntityFilter, "No application entity filter"); - PrintErrorCode(ErrorCode_NoSopClassOrInstance, "DicomUserConnection: Unable to find the SOP class and instance"); - PrintErrorCode(ErrorCode_NoPresentationContext, "DicomUserConnection: No acceptable presentation context for modality"); - PrintErrorCode(ErrorCode_DicomFindUnavailable, "DicomUserConnection: The C-FIND command is not supported by the remote SCP"); - PrintErrorCode(ErrorCode_DicomMoveUnavailable, "DicomUserConnection: The C-MOVE command is not supported by the remote SCP"); - PrintErrorCode(ErrorCode_CannotStoreInstance, "Cannot store an instance"); - PrintErrorCode(ErrorCode_CreateDicomNotString, "Only string values are supported when creating DICOM instances"); - PrintErrorCode(ErrorCode_CreateDicomOverrideTag, "Trying to override a value inherited from a parent module"); - PrintErrorCode(ErrorCode_CreateDicomUseContent, "Use \"Content\" to inject an image into a new DICOM instance"); - PrintErrorCode(ErrorCode_CreateDicomNoPayload, "No payload is present for one instance in the series"); - PrintErrorCode(ErrorCode_CreateDicomUseDataUriScheme, "The payload of the DICOM instance must be specified according to Data URI scheme"); - PrintErrorCode(ErrorCode_CreateDicomBadParent, "Trying to attach a new DICOM instance to an inexistent resource"); - PrintErrorCode(ErrorCode_CreateDicomParentIsInstance, "Trying to attach a new DICOM instance to an instance (must be a series, study or patient)"); - PrintErrorCode(ErrorCode_CreateDicomParentEncoding, "Unable to get the encoding of the parent resource"); - PrintErrorCode(ErrorCode_UnknownModality, "Unknown modality"); - PrintErrorCode(ErrorCode_BadJobOrdering, "Bad ordering of filters in a job"); - PrintErrorCode(ErrorCode_JsonToLuaTable, "Cannot convert the given JSON object to a Lua table"); - PrintErrorCode(ErrorCode_CannotCreateLua, "Cannot create the Lua context"); - PrintErrorCode(ErrorCode_CannotExecuteLua, "Cannot execute a Lua command"); - PrintErrorCode(ErrorCode_LuaAlreadyExecuted, "Arguments cannot be pushed after the Lua function is executed"); - PrintErrorCode(ErrorCode_LuaBadOutput, "The Lua function does not give the expected number of outputs"); - PrintErrorCode(ErrorCode_NotLuaPredicate, "The Lua function is not a predicate (only true/false outputs allowed)"); - PrintErrorCode(ErrorCode_LuaReturnsNoString, "The Lua function does not return a string"); - PrintErrorCode(ErrorCode_StorageAreaAlreadyRegistered, "Another plugin has already registered a custom storage area"); - PrintErrorCode(ErrorCode_DatabaseBackendAlreadyRegistered, "Another plugin has already registered a custom database back-end"); - PrintErrorCode(ErrorCode_DatabaseNotInitialized, "Plugin trying to call the database during its initialization"); - PrintErrorCode(ErrorCode_SslDisabled, "Orthanc has been built without SSL support"); - PrintErrorCode(ErrorCode_CannotOrderSlices, "Unable to order the slices of the series"); - PrintErrorCode(ErrorCode_NoWorklistHandler, "No request handler factory for DICOM C-Find Modality SCP"); - PrintErrorCode(ErrorCode_AlreadyExistingTag, "Cannot override the value of a tag that already exists"); - PrintErrorCode(ErrorCode_NoCGetHandler, "No request handler factory for DICOM C-GET SCP"); - PrintErrorCode(ErrorCode_NoStorageCommitmentHandler, "No request handler factory for DICOM N-ACTION SCP (storage commitment)"); - PrintErrorCode(ErrorCode_UnsupportedMediaType, "Unsupported media type"); - } - - std::cout << std::endl; -} - - - -#if ORTHANC_ENABLE_PLUGINS == 1 -static void LoadPlugins(OrthancPlugins& plugins) -{ - std::list path; - - { - OrthancConfiguration::ReaderLock lock; - lock.GetConfiguration().GetListOfStringsParameter(path, "Plugins"); - } - - for (std::list::const_iterator - it = path.begin(); it != path.end(); ++it) - { - std::string path; - - { - OrthancConfiguration::ReaderLock lock; - path = lock.GetConfiguration().InterpretStringParameterAsPath(*it); - } - - LOG(WARNING) << "Loading plugin(s) from: " << path; - plugins.GetManager().RegisterPlugin(path); - } -} -#endif - - - -// Returns "true" if restart is required -static bool WaitForExit(ServerContext& context, - OrthancRestApi& restApi) -{ - LOG(WARNING) << "Orthanc has started"; - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (context.HasPlugins()) - { - context.GetPlugins().SignalOrthancStarted(); - } -#endif - - context.GetLuaScripting().Start(); - context.GetLuaScripting().Execute("Initialize"); - - bool restart; - - for (;;) - { - ServerBarrierEvent event = SystemToolbox::ServerBarrier(restApi.LeaveBarrierFlag()); - restart = restApi.IsResetRequestReceived(); - - if (!restart && - event == ServerBarrierEvent_Reload) - { - // Handling of SIGHUP - - OrthancConfiguration::ReaderLock lock; - if (lock.GetConfiguration().HasConfigurationChanged()) - { - LOG(WARNING) << "A SIGHUP signal has been received, resetting Orthanc"; - Logging::Flush(); - restart = true; - break; - } - else - { - LOG(WARNING) << "A SIGHUP signal has been received, but is ignored " - << "as the configuration has not changed on the disk"; - Logging::Flush(); - continue; - } - } - else - { - break; - } - } - - context.GetLuaScripting().Execute("Finalize"); - context.GetLuaScripting().Stop(); - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (context.HasPlugins()) - { - context.GetPlugins().SignalOrthancStopped(); - } -#endif - - if (restart) - { - LOG(WARNING) << "Reset request received, restarting Orthanc"; - } - - // We're done - LOG(WARNING) << "Orthanc is stopping"; - - return restart; -} - - - -static bool StartHttpServer(ServerContext& context, - OrthancRestApi& restApi, - OrthancPlugins* plugins) -{ - bool httpServerEnabled; - - { - OrthancConfiguration::ReaderLock lock; - httpServerEnabled = lock.GetConfiguration().GetBooleanParameter("HttpServerEnabled", true); - } - - if (!httpServerEnabled) - { - LOG(WARNING) << "The HTTP server is disabled"; - return WaitForExit(context, restApi); - } - else - { - MyIncomingHttpRequestFilter httpFilter(context, plugins); - HttpServer httpServer; - bool httpDescribeErrors; - -#if ORTHANC_ENABLE_MONGOOSE == 1 - const bool defaultKeepAlive = false; -#elif ORTHANC_ENABLE_CIVETWEB == 1 - const bool defaultKeepAlive = true; -#else -# error "Either Mongoose or Civetweb must be enabled to compile this file" -#endif - - { - OrthancConfiguration::ReaderLock lock; - - httpDescribeErrors = lock.GetConfiguration().GetBooleanParameter("HttpDescribeErrors", true); - - // HTTP server - httpServer.SetThreadsCount(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpThreadsCount", 50)); - httpServer.SetPortNumber(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpPort", 8042)); - httpServer.SetRemoteAccessAllowed(lock.GetConfiguration().GetBooleanParameter("RemoteAccessAllowed", false)); - httpServer.SetKeepAliveEnabled(lock.GetConfiguration().GetBooleanParameter("KeepAlive", defaultKeepAlive)); - httpServer.SetHttpCompressionEnabled(lock.GetConfiguration().GetBooleanParameter("HttpCompressionEnabled", true)); - httpServer.SetTcpNoDelay(lock.GetConfiguration().GetBooleanParameter("TcpNoDelay", true)); - httpServer.SetRequestTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpRequestTimeout", 30)); - - // Let's assume that the HTTP server is secure - context.SetHttpServerSecure(true); - - bool authenticationEnabled; - if (lock.GetConfiguration().LookupBooleanParameter(authenticationEnabled, "AuthenticationEnabled")) - { - httpServer.SetAuthenticationEnabled(authenticationEnabled); - - if (httpServer.IsRemoteAccessAllowed() && - !authenticationEnabled) - { - LOG(WARNING) << "====> Remote access is enabled while user authentication is explicitly disabled, " - << "your setup is POSSIBLY INSECURE <===="; - context.SetHttpServerSecure(false); - } - } - else if (httpServer.IsRemoteAccessAllowed()) - { - // Starting with Orthanc 1.5.8, it is impossible to enable - // remote access without having explicitly disabled user - // authentication. - LOG(WARNING) << "Remote access is allowed but \"AuthenticationEnabled\" is not in the configuration, " - << "automatically enabling HTTP authentication for security"; - httpServer.SetAuthenticationEnabled(true); - } - else - { - // If Orthanc only listens on the localhost, it is OK to have - // "AuthenticationEnabled" disabled - httpServer.SetAuthenticationEnabled(false); - } - - bool hasUsers = lock.GetConfiguration().SetupRegisteredUsers(httpServer); - - if (httpServer.IsAuthenticationEnabled() && - !hasUsers) - { - if (httpServer.IsRemoteAccessAllowed()) - { - /** - * Starting with Orthanc 1.5.8, if no user is explicitly - * defined while remote access is allowed, we create a - * default user, and Orthanc Explorer shows a warning - * message about an "Insecure setup". This convention is - * used in Docker images "jodogne/orthanc", - * "jodogne/orthanc-plugins" and "osimis/orthanc". - **/ - LOG(WARNING) << "====> HTTP authentication is enabled, but no user is declared. " - << "Creating a default user: Review your configuration option \"RegisteredUsers\". " - << "Your setup is INSECURE <===="; - - context.SetHttpServerSecure(false); - - // This is the username/password of the default user in Orthanc. - httpServer.RegisterUser("orthanc", "orthanc"); - } - else - { - LOG(WARNING) << "HTTP authentication is enabled, but no user is declared, " - << "check the value of configuration option \"RegisteredUsers\""; - } - } - - if (lock.GetConfiguration().GetBooleanParameter("SslEnabled", false)) - { - std::string certificate = lock.GetConfiguration().InterpretStringParameterAsPath( - lock.GetConfiguration().GetStringParameter("SslCertificate", "certificate.pem")); - httpServer.SetSslEnabled(true); - httpServer.SetSslCertificate(certificate.c_str()); - } - else - { - httpServer.SetSslEnabled(false); - } - - if (lock.GetConfiguration().GetBooleanParameter("ExecuteLuaEnabled", false)) - { - context.SetExecuteLuaEnabled(true); - LOG(WARNING) << "====> Remote LUA script execution is enabled. Review your configuration option \"ExecuteLuaEnabled\". " - << "Your setup is POSSIBLY INSECURE <===="; - } - else - { - context.SetExecuteLuaEnabled(false); - LOG(WARNING) << "Remote LUA script execution is disabled"; - } - } - - MyHttpExceptionFormatter exceptionFormatter(httpDescribeErrors, plugins); - - httpServer.SetIncomingHttpRequestFilter(httpFilter); - httpServer.SetHttpExceptionFormatter(exceptionFormatter); - httpServer.Register(context.GetHttpHandler()); - - if (httpServer.GetPortNumber() < 1024) - { - LOG(WARNING) << "The HTTP port is privileged (" - << httpServer.GetPortNumber() << " is below 1024), " - << "make sure you run Orthanc as root/administrator"; - } - - httpServer.Start(); - - bool restart = WaitForExit(context, restApi); - - httpServer.Stop(); - LOG(WARNING) << " HTTP server has stopped"; - - return restart; - } -} - - -static bool StartDicomServer(ServerContext& context, - OrthancRestApi& restApi, - OrthancPlugins* plugins) -{ - bool dicomServerEnabled; - - { - OrthancConfiguration::ReaderLock lock; - dicomServerEnabled = lock.GetConfiguration().GetBooleanParameter("DicomServerEnabled", true); - } - - if (!dicomServerEnabled) - { - LOG(WARNING) << "The DICOM server is disabled"; - return StartHttpServer(context, restApi, plugins); - } - else - { - MyDicomServerFactory serverFactory(context); - OrthancApplicationEntityFilter dicomFilter(context); - ModalitiesFromConfiguration modalities; - - // Setup the DICOM server - DicomServer dicomServer; - dicomServer.SetRemoteModalities(modalities); - dicomServer.SetStoreRequestHandlerFactory(serverFactory); - dicomServer.SetMoveRequestHandlerFactory(serverFactory); - dicomServer.SetGetRequestHandlerFactory(serverFactory); - dicomServer.SetFindRequestHandlerFactory(serverFactory); - dicomServer.SetStorageCommitmentRequestHandlerFactory(serverFactory); - - { - OrthancConfiguration::ReaderLock lock; - dicomServer.SetCalledApplicationEntityTitleCheck(lock.GetConfiguration().GetBooleanParameter("DicomCheckCalledAet", false)); - dicomServer.SetAssociationTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomScpTimeout", 30)); - dicomServer.SetPortNumber(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomPort", 4242)); - dicomServer.SetApplicationEntityTitle(lock.GetConfiguration().GetStringParameter("DicomAet", "ORTHANC")); - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (plugins != NULL) - { - if (plugins->HasWorklistHandler()) - { - dicomServer.SetWorklistRequestHandlerFactory(*plugins); - } - - if (plugins->HasFindHandler()) - { - dicomServer.SetFindRequestHandlerFactory(*plugins); - } - - if (plugins->HasMoveHandler()) - { - dicomServer.SetMoveRequestHandlerFactory(*plugins); - } - } -#endif - - dicomServer.SetApplicationEntityFilter(dicomFilter); - - if (dicomServer.GetPortNumber() < 1024) - { - LOG(WARNING) << "The DICOM port is privileged (" - << dicomServer.GetPortNumber() << " is below 1024), " - << "make sure you run Orthanc as root/administrator"; - } - - dicomServer.Start(); - LOG(WARNING) << "DICOM server listening with AET " << dicomServer.GetApplicationEntityTitle() - << " on port: " << dicomServer.GetPortNumber(); - - bool restart = false; - ErrorCode error = ErrorCode_Success; - - try - { - restart = StartHttpServer(context, restApi, plugins); - } - catch (OrthancException& e) - { - error = e.GetErrorCode(); - } - - dicomServer.Stop(); - LOG(WARNING) << " DICOM server has stopped"; - - serverFactory.Done(); - - if (error != ErrorCode_Success) - { - throw OrthancException(error); - } - - return restart; - } -} - - -static bool ConfigureHttpHandler(ServerContext& context, - OrthancPlugins *plugins, - bool loadJobsFromDatabase) -{ -#if ORTHANC_ENABLE_PLUGINS == 1 - // By order of priority, first apply the "plugins" layer, so that - // plugins can overwrite the built-in REST API of Orthanc - if (plugins) - { - assert(context.HasPlugins()); - context.GetHttpHandler().Register(*plugins, false); - } -#endif - - // Secondly, apply the "static resources" layer -#if ORTHANC_STANDALONE == 1 - EmbeddedResourceHttpHandler staticResources("/app", EmbeddedResources::ORTHANC_EXPLORER); -#else - FilesystemHttpHandler staticResources("/app", ORTHANC_PATH "/OrthancExplorer"); -#endif - - context.GetHttpHandler().Register(staticResources, false); - - // Thirdly, consider the built-in REST API of Orthanc - OrthancRestApi restApi(context); - context.GetHttpHandler().Register(restApi, true); - - context.SetupJobsEngine(false /* not running unit tests */, loadJobsFromDatabase); - - bool restart = StartDicomServer(context, restApi, plugins); - - context.Stop(); - - return restart; -} - - -static void UpgradeDatabase(IDatabaseWrapper& database, - IStorageArea& storageArea) -{ - // Upgrade the schema of the database, if needed - unsigned int currentVersion = database.GetDatabaseVersion(); - - LOG(WARNING) << "Starting the upgrade of the database schema"; - LOG(WARNING) << "Current database version: " << currentVersion; - LOG(WARNING) << "Database version expected by Orthanc: " << ORTHANC_DATABASE_VERSION; - - if (currentVersion == ORTHANC_DATABASE_VERSION) - { - LOG(WARNING) << "No upgrade is needed, start Orthanc without the \"--upgrade\" argument"; - return; - } - - if (currentVersion > ORTHANC_DATABASE_VERSION) - { - throw OrthancException(ErrorCode_IncompatibleDatabaseVersion, - "The version of the database schema (" + - boost::lexical_cast(currentVersion) + - ") is too recent for this version of Orthanc. Please upgrade Orthanc."); - } - - LOG(WARNING) << "Upgrading the database from schema version " - << currentVersion << " to " << ORTHANC_DATABASE_VERSION; - - try - { - database.Upgrade(ORTHANC_DATABASE_VERSION, storageArea); - } - catch (OrthancException&) - { - LOG(ERROR) << "Unable to run the automated upgrade, please use the replication instructions: " - << "http://book.orthanc-server.com/users/replication.html"; - throw; - } - - // Sanity check - currentVersion = database.GetDatabaseVersion(); - if (ORTHANC_DATABASE_VERSION != currentVersion) - { - throw OrthancException(ErrorCode_IncompatibleDatabaseVersion, - "The database schema was not properly upgraded, it is still at version " + - boost::lexical_cast(currentVersion)); - } - else - { - LOG(WARNING) << "The database schema was successfully upgraded, " - << "you can now start Orthanc without the \"--upgrade\" argument"; - } -} - - - -namespace -{ - class ServerContextConfigurator : public boost::noncopyable - { - private: - ServerContext& context_; - OrthancPlugins* plugins_; - - public: - ServerContextConfigurator(ServerContext& context, - OrthancPlugins* plugins) : - context_(context), - plugins_(plugins) - { - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().SetServerIndex(context.GetIndex()); - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (plugins_ != NULL) - { - plugins_->SetServerContext(context_); - context_.SetPlugins(*plugins_); - } -#endif - } - - ~ServerContextConfigurator() - { - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().ResetServerIndex(); - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (plugins_ != NULL) - { - plugins_->ResetServerContext(); - context_.ResetPlugins(); - } -#endif - } - }; -} - - -static bool ConfigureServerContext(IDatabaseWrapper& database, - IStorageArea& storageArea, - OrthancPlugins *plugins, - bool loadJobsFromDatabase) -{ - size_t maxCompletedJobs; - - { - OrthancConfiguration::ReaderLock lock; - - // These configuration options must be set before creating the - // ServerContext, otherwise the possible Lua scripts will not be - // able to properly issue HTTP/HTTPS queries - HttpClient::ConfigureSsl(lock.GetConfiguration().GetBooleanParameter("HttpsVerifyPeers", true), - lock.GetConfiguration().InterpretStringParameterAsPath - (lock.GetConfiguration().GetStringParameter("HttpsCACertificates", ""))); - HttpClient::SetDefaultVerbose(lock.GetConfiguration().GetBooleanParameter("HttpVerbose", false)); - - // The value "0" below makes the class HttpClient use its default - // value (DEFAULT_HTTP_TIMEOUT = 60 seconds in Orthanc 1.5.7) - HttpClient::SetDefaultTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpTimeout", 0)); - - HttpClient::SetDefaultProxy(lock.GetConfiguration().GetStringParameter("HttpProxy", "")); - - DicomAssociationParameters::SetDefaultTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomScuTimeout", 10)); - - maxCompletedJobs = lock.GetConfiguration().GetUnsignedIntegerParameter("JobsHistorySize", 10); - - if (maxCompletedJobs == 0) - { - LOG(WARNING) << "Setting option \"JobsHistorySize\" to zero is not recommended"; - } - } - - ServerContext context(database, storageArea, false /* not running unit tests */, maxCompletedJobs); - - { - OrthancConfiguration::ReaderLock lock; - - context.SetCompressionEnabled(lock.GetConfiguration().GetBooleanParameter("StorageCompression", false)); - context.SetStoreMD5ForAttachments(lock.GetConfiguration().GetBooleanParameter("StoreMD5ForAttachments", true)); - - // New option in Orthanc 1.4.2 - context.SetOverwriteInstances(lock.GetConfiguration().GetBooleanParameter("OverwriteInstances", false)); - - try - { - context.GetIndex().SetMaximumPatientCount(lock.GetConfiguration().GetUnsignedIntegerParameter("MaximumPatientCount", 0)); - } - catch (...) - { - context.GetIndex().SetMaximumPatientCount(0); - } - - try - { - uint64_t size = lock.GetConfiguration().GetUnsignedIntegerParameter("MaximumStorageSize", 0); - context.GetIndex().SetMaximumStorageSize(size * 1024 * 1024); - } - catch (...) - { - context.GetIndex().SetMaximumStorageSize(0); - } - } - - { - ServerContextConfigurator configurator(context, plugins); - - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().LoadModalitiesAndPeers(); - } - - return ConfigureHttpHandler(context, plugins, loadJobsFromDatabase); - } -} - - -static bool ConfigureDatabase(IDatabaseWrapper& database, - IStorageArea& storageArea, - OrthancPlugins *plugins, - bool upgradeDatabase, - bool loadJobsFromDatabase) -{ - database.Open(); - - unsigned int currentVersion = database.GetDatabaseVersion(); - - if (upgradeDatabase) - { - UpgradeDatabase(database, storageArea); - return false; // Stop and don't restart Orthanc (cf. issue 29) - } - else if (currentVersion != ORTHANC_DATABASE_VERSION) - { - throw OrthancException(ErrorCode_IncompatibleDatabaseVersion, - "The database schema must be upgraded from version " + - boost::lexical_cast(currentVersion) + " to " + - boost::lexical_cast(ORTHANC_DATABASE_VERSION) + - ": Please run Orthanc with the \"--upgrade\" argument"); - } - - bool success = ConfigureServerContext - (database, storageArea, plugins, loadJobsFromDatabase); - - database.Close(); - - return success; -} - - -static bool ConfigurePlugins(int argc, - char* argv[], - bool upgradeDatabase, - bool loadJobsFromDatabase) -{ - std::unique_ptr databasePtr; - std::unique_ptr storage; - -#if ORTHANC_ENABLE_PLUGINS == 1 - OrthancPlugins plugins; - plugins.SetCommandLineArguments(argc, argv); - LoadPlugins(plugins); - - IDatabaseWrapper* database = NULL; - if (plugins.HasDatabaseBackend()) - { - LOG(WARNING) << "Using a custom database from plugins"; - database = &plugins.GetDatabaseBackend(); - } - else - { - databasePtr.reset(CreateDatabaseWrapper()); - database = databasePtr.get(); - } - - if (plugins.HasStorageArea()) - { - LOG(WARNING) << "Using a custom storage area from plugins"; - storage.reset(plugins.CreateStorageArea()); - } - else - { - storage.reset(CreateStorageArea()); - } - - assert(database != NULL); - assert(storage.get() != NULL); - - return ConfigureDatabase(*database, *storage, &plugins, - upgradeDatabase, loadJobsFromDatabase); - -#elif ORTHANC_ENABLE_PLUGINS == 0 - // The plugins are disabled - - databasePtr.reset(CreateDatabaseWrapper()); - storage.reset(CreateStorageArea()); - - assert(databasePtr.get() != NULL); - assert(storage.get() != NULL); - - return ConfigureDatabase(*databasePtr, *storage, NULL, - upgradeDatabase, loadJobsFromDatabase); - -#else -# error The macro ORTHANC_ENABLE_PLUGINS must be set to 0 or 1 -#endif -} - - -static bool StartOrthanc(int argc, - char* argv[], - bool upgradeDatabase, - bool loadJobsFromDatabase) -{ - return ConfigurePlugins(argc, argv, upgradeDatabase, loadJobsFromDatabase); -} - - -static bool DisplayPerformanceWarning() -{ - (void) DisplayPerformanceWarning; // Disable warning about unused function - LOG(WARNING) << "Performance warning: Non-release build, runtime debug assertions are turned on"; - return true; -} - - -int main(int argc, char* argv[]) -{ - Logging::Initialize(); - - bool upgradeDatabase = false; - bool loadJobsFromDatabase = true; - const char* configurationFile = NULL; - - - /** - * Parse the command-line options. - **/ - - for (int i = 1; i < argc; i++) - { - std::string argument(argv[i]); - - if (argument.empty()) - { - // Ignore empty arguments - } - else if (argument[0] != '-') - { - if (configurationFile != NULL) - { - LOG(ERROR) << "More than one configuration path were provided on the command line, aborting"; - return -1; - } - else - { - // Use the first argument that does not start with a "-" as - // the configuration file - - // TODO WHAT IS THE ENCODING? - configurationFile = argv[i]; - } - } - else if (argument == "--errors") - { - PrintErrors(argv[0]); - return 0; - } - else if (argument == "--help") - { - PrintHelp(argv[0]); - return 0; - } - else if (argument == "--version") - { - PrintVersion(argv[0]); - return 0; - } - else if (argument == "--verbose") - { - Logging::EnableInfoLevel(true); - } - else if (argument == "--trace") - { - Logging::EnableTraceLevel(true); - } - else if (boost::starts_with(argument, "--logdir=")) - { - // TODO WHAT IS THE ENCODING? - std::string directory = argument.substr(9); - - try - { - Logging::SetTargetFolder(directory); - } - catch (OrthancException&) - { - LOG(ERROR) << "The directory where to store the log files (" - << directory << ") is inexistent, aborting."; - return -1; - } - } - else if (boost::starts_with(argument, "--logfile=")) - { - // TODO WHAT IS THE ENCODING? - std::string file = argument.substr(10); - - try - { - Logging::SetTargetFile(file); - } - catch (OrthancException&) - { - LOG(ERROR) << "Cannot write to the specified log file (" - << file << "), aborting."; - return -1; - } - } - else if (argument == "--upgrade") - { - upgradeDatabase = true; - } - else if (argument == "--no-jobs") - { - loadJobsFromDatabase = false; - } - else if (boost::starts_with(argument, "--config=")) - { - // TODO WHAT IS THE ENCODING? - std::string configurationSample; - GetFileResource(configurationSample, EmbeddedResources::CONFIGURATION_SAMPLE); - -#if defined(_WIN32) - // Replace UNIX newlines with DOS newlines - boost::replace_all(configurationSample, "\n", "\r\n"); -#endif - - std::string target = argument.substr(9); - - try - { - if (target == "-") - { - // New in 1.5.8: Print to stdout - std::cout << configurationSample; - } - else - { - SystemToolbox::WriteFile(configurationSample, target); - } - return 0; - } - catch (OrthancException&) - { - LOG(ERROR) << "Cannot write sample configuration as file \"" << target << "\""; - return -1; - } - } - else - { - LOG(WARNING) << "Option unsupported by the core of Orthanc: " << argument; - } - } - - - /** - * Launch Orthanc. - **/ - - { - std::string version(ORTHANC_VERSION); - - if (std::string(ORTHANC_VERSION) == "mainline") - { - try - { - boost::filesystem::path exe(SystemToolbox::GetPathToExecutable()); - std::time_t creation = boost::filesystem::last_write_time(exe); - boost::posix_time::ptime converted(boost::posix_time::from_time_t(creation)); - version += " (" + boost::posix_time::to_iso_string(converted) + ")"; - } - catch (...) - { - } - } - - LOG(WARNING) << "Orthanc version: " << version; - assert(DisplayPerformanceWarning()); - } - - int status = 0; - try - { - for (;;) - { - OrthancInitialize(configurationFile); - - bool restart = StartOrthanc(argc, argv, upgradeDatabase, loadJobsFromDatabase); - if (restart) - { - OrthancFinalize(); - LOG(WARNING) << "Logging system is resetting"; - Logging::Reset(); - } - else - { - break; - } - } - } - catch (const OrthancException& e) - { - LOG(ERROR) << "Uncaught exception, stopping now: [" << e.What() << "] (code " << e.GetErrorCode() << ")"; -#if defined(_WIN32) - if (e.GetErrorCode() >= ErrorCode_START_PLUGINS) - { - status = static_cast(ErrorCode_Plugin); - } - else - { - status = static_cast(e.GetErrorCode()); - } - -#else - status = -1; -#endif - } - catch (const std::exception& e) - { - LOG(ERROR) << "Uncaught exception, stopping now: [" << e.what() << "]"; - status = -1; - } - catch (const std::string& s) - { - LOG(ERROR) << "Uncaught exception, stopping now: [" << s << "]"; - status = -1; - } - catch (...) - { - LOG(ERROR) << "Native exception, stopping now. Check your plugins, if any."; - status = -1; - } - - OrthancFinalize(); - - LOG(WARNING) << "Orthanc has stopped"; - - Logging::Finalize(); - - return status; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,891 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "OrthancConfiguration.h" - -#include "../Core/HttpServer/HttpServer.h" -#include "../Core/Logging.h" -#include "../Core/OrthancException.h" -#include "../Core/SystemToolbox.h" -#include "../Core/TemporaryFile.h" -#include "../Core/Toolbox.h" - -#include "ServerIndex.h" - - -static const char* const DICOM_MODALITIES = "DicomModalities"; -static const char* const DICOM_MODALITIES_IN_DB = "DicomModalitiesInDatabase"; -static const char* const ORTHANC_PEERS = "OrthancPeers"; -static const char* const ORTHANC_PEERS_IN_DB = "OrthancPeersInDatabase"; -static const char* const TEMPORARY_DIRECTORY = "TemporaryDirectory"; - -namespace Orthanc -{ - static void AddFileToConfiguration(Json::Value& target, - const boost::filesystem::path& path) - { - std::map env; - SystemToolbox::GetEnvironmentVariables(env); - - LOG(WARNING) << "Reading the configuration from: " << path; - - Json::Value config; - - { - std::string content; - SystemToolbox::ReadFile(content, path.string()); - - content = Toolbox::SubstituteVariables(content, env); - - Json::Value tmp; - Json::Reader reader; - if (!reader.parse(content, tmp) || - tmp.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadJson, - "The configuration file does not follow the JSON syntax: " + path.string()); - } - - Toolbox::CopyJsonWithoutComments(config, tmp); - } - - if (target.size() == 0) - { - target = config; - } - else - { - // Merge the newly-added file with the previous content of "target" - Json::Value::Members members = config.getMemberNames(); - for (Json::Value::ArrayIndex i = 0; i < members.size(); i++) - { - if (target.isMember(members[i])) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The configuration section \"" + members[i] + - "\" is defined in 2 different configuration files"); - } - else - { - target[members[i]] = config[members[i]]; - } - } - } - } - - - static void ScanFolderForConfiguration(Json::Value& target, - const char* folder) - { - using namespace boost::filesystem; - - LOG(WARNING) << "Scanning folder \"" << folder << "\" for configuration files"; - - directory_iterator end_it; // default construction yields past-the-end - for (directory_iterator it(folder); - it != end_it; - ++it) - { - if (!is_directory(it->status())) - { - std::string extension = boost::filesystem::extension(it->path()); - Toolbox::ToLowerCase(extension); - - if (extension == ".json") - { - AddFileToConfiguration(target, it->path().string()); - } - } - } - } - - - static void ReadConfiguration(Json::Value& target, - const char* configurationFile) - { - target = Json::objectValue; - - if (configurationFile != NULL) - { - if (!boost::filesystem::exists(configurationFile)) - { - throw OrthancException(ErrorCode_InexistentFile, - "Inexistent path to configuration: " + - std::string(configurationFile)); - } - - if (boost::filesystem::is_directory(configurationFile)) - { - ScanFolderForConfiguration(target, configurationFile); - } - else - { - AddFileToConfiguration(target, configurationFile); - } - } - else - { -#if ORTHANC_STANDALONE == 1 - // No default path for the standalone configuration - LOG(WARNING) << "Using the default Orthanc configuration"; - return; - -#else - // In a non-standalone build, we use the - // "Resources/Configuration.json" from the Orthanc source code - - boost::filesystem::path p = ORTHANC_PATH; - p /= "Resources"; - p /= "Configuration.json"; - - AddFileToConfiguration(target, p); -#endif - } - } - - - static void CheckAlphanumeric(const std::string& s) - { - for (size_t j = 0; j < s.size(); j++) - { - if (!isalnum(s[j]) && - s[j] != '-') - { - throw OrthancException(ErrorCode_BadFileFormat, - "Only alphanumeric and dash characters are allowed " - "in the names of modalities/peers, but found: " + s); - } - } - } - - - void OrthancConfiguration::LoadModalitiesFromJson(const Json::Value& source) - { - modalities_.clear(); - - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Bad format of the \"" + std::string(DICOM_MODALITIES) + - "\" configuration section"); - } - - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - CheckAlphanumeric(name); - - RemoteModalityParameters modality; - modality.Unserialize(source[name]); - modalities_[name] = modality; - } - } - - - void OrthancConfiguration::LoadPeersFromJson(const Json::Value& source) - { - peers_.clear(); - - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Bad format of the \"" + std::string(ORTHANC_PEERS) + - "\" configuration section"); - } - - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - CheckAlphanumeric(name); - - WebServiceParameters peer; - peer.Unserialize(source[name]); - peers_[name] = peer; - } - } - - - void OrthancConfiguration::LoadModalities() - { - if (GetBooleanParameter(DICOM_MODALITIES_IN_DB, false)) - { - // Modalities are stored in the database - if (serverIndex_ == NULL) - { - throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - std::string property = serverIndex_->GetGlobalProperty(GlobalProperty_Modalities, "{}"); - - Json::Reader reader; - Json::Value modalities; - if (reader.parse(property, modalities)) - { - LoadModalitiesFromJson(modalities); - } - else - { - throw OrthancException(ErrorCode_InternalError, - "Cannot unserialize the list of modalities from the Orthanc database"); - } - } - } - else - { - // Modalities are stored in the configuration files - if (json_.isMember(DICOM_MODALITIES)) - { - LoadModalitiesFromJson(json_[DICOM_MODALITIES]); - } - else - { - modalities_.clear(); - } - } - } - - void OrthancConfiguration::LoadPeers() - { - if (GetBooleanParameter(ORTHANC_PEERS_IN_DB, false)) - { - // Peers are stored in the database - if (serverIndex_ == NULL) - { - throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - std::string property = serverIndex_->GetGlobalProperty(GlobalProperty_Peers, "{}"); - - Json::Reader reader; - Json::Value peers; - if (reader.parse(property, peers)) - { - LoadPeersFromJson(peers); - } - else - { - throw OrthancException(ErrorCode_InternalError, - "Cannot unserialize the list of peers from the Orthanc database"); - } - } - } - else - { - // Peers are stored in the configuration files - if (json_.isMember(ORTHANC_PEERS)) - { - LoadPeersFromJson(json_[ORTHANC_PEERS]); - } - else - { - peers_.clear(); - } - } - } - - - void OrthancConfiguration::SaveModalitiesToJson(Json::Value& target) - { - target = Json::objectValue; - - for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it) - { - Json::Value modality; - it->second.Serialize(modality, true /* force advanced format */); - - target[it->first] = modality; - } - } - - - void OrthancConfiguration::SavePeersToJson(Json::Value& target) - { - target = Json::objectValue; - - for (Peers::const_iterator it = peers_.begin(); it != peers_.end(); ++it) - { - Json::Value peer; - it->second.Serialize(peer, - false /* use simple format if possible */, - true /* include passwords */); - - target[it->first] = peer; - } - } - - - void OrthancConfiguration::SaveModalities() - { - if (GetBooleanParameter(DICOM_MODALITIES_IN_DB, false)) - { - // Modalities are stored in the database - if (serverIndex_ == NULL) - { - throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - Json::Value modalities; - SaveModalitiesToJson(modalities); - - Json::FastWriter writer; - std::string s = writer.write(modalities); - - serverIndex_->SetGlobalProperty(GlobalProperty_Modalities, s); - } - } - else - { - // Modalities are stored in the configuration files - if (!modalities_.empty() || - json_.isMember(DICOM_MODALITIES)) - { - SaveModalitiesToJson(json_[DICOM_MODALITIES]); - } - } - } - - - void OrthancConfiguration::SavePeers() - { - if (GetBooleanParameter(ORTHANC_PEERS_IN_DB, false)) - { - // Peers are stored in the database - if (serverIndex_ == NULL) - { - throw Orthanc::OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - Json::Value peers; - SavePeersToJson(peers); - - Json::FastWriter writer; - std::string s = writer.write(peers); - - serverIndex_->SetGlobalProperty(GlobalProperty_Peers, s); - } - } - else - { - // Peers are stored in the configuration files - if (!peers_.empty() || - json_.isMember(ORTHANC_PEERS)) - { - SavePeersToJson(json_[ORTHANC_PEERS]); - } - } - } - - - OrthancConfiguration& OrthancConfiguration::GetInstance() - { - static OrthancConfiguration configuration; - return configuration; - } - - - bool OrthancConfiguration::LookupStringParameter(std::string& target, - const std::string& parameter) const - { - if (json_.isMember(parameter)) - { - if (json_[parameter].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadParameterType, - "The configuration option \"" + parameter + "\" must be a string"); - } - else - { - target = json_[parameter].asString(); - return true; - } - } - else - { - return false; - } - } - - - std::string OrthancConfiguration::GetStringParameter(const std::string& parameter, - const std::string& defaultValue) const - { - std::string value; - if (LookupStringParameter(value, parameter)) - { - return value; - } - else - { - return defaultValue; - } - } - - - int OrthancConfiguration::GetIntegerParameter(const std::string& parameter, - int defaultValue) const - { - if (json_.isMember(parameter)) - { - if (json_[parameter].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadParameterType, - "The configuration option \"" + parameter + "\" must be an integer"); - } - else - { - return json_[parameter].asInt(); - } - } - else - { - return defaultValue; - } - } - - - unsigned int OrthancConfiguration::GetUnsignedIntegerParameter( - const std::string& parameter, - unsigned int defaultValue) const - { - int v = GetIntegerParameter(parameter, defaultValue); - - if (v < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "The configuration option \"" + parameter + "\" must be a positive integer"); - } - else - { - return static_cast(v); - } - } - - - bool OrthancConfiguration::LookupBooleanParameter(bool& target, - const std::string& parameter) const - { - if (json_.isMember(parameter)) - { - if (json_[parameter].type() != Json::booleanValue) - { - throw OrthancException(ErrorCode_BadParameterType, - "The configuration option \"" + parameter + - "\" must be a Boolean (true or false)"); - } - else - { - target = json_[parameter].asBool(); - return true; - } - } - else - { - return false; - } - } - - - bool OrthancConfiguration::GetBooleanParameter(const std::string& parameter, - bool defaultValue) const - { - bool value; - if (LookupBooleanParameter(value, parameter)) - { - return value; - } - else - { - return defaultValue; - } - } - - - void OrthancConfiguration::Read(const char* configurationFile) - { - // Read the content of the configuration - configurationFileArg_ = configurationFile; - ReadConfiguration(json_, configurationFile); - - // Adapt the paths to the configurations - defaultDirectory_ = boost::filesystem::current_path(); - configurationAbsolutePath_ = ""; - - if (configurationFile) - { - if (boost::filesystem::is_directory(configurationFile)) - { - defaultDirectory_ = boost::filesystem::path(configurationFile); - configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).parent_path().string(); - } - else - { - defaultDirectory_ = boost::filesystem::path(configurationFile).parent_path(); - configurationAbsolutePath_ = boost::filesystem::absolute(configurationFile).string(); - } - } - else - { -#if ORTHANC_STANDALONE != 1 - // In a non-standalone build, we use the - // "Resources/Configuration.json" from the Orthanc source code - - boost::filesystem::path p = ORTHANC_PATH; - p /= "Resources"; - p /= "Configuration.json"; - configurationAbsolutePath_ = boost::filesystem::absolute(p).string(); -#endif - } - } - - - void OrthancConfiguration::LoadModalitiesAndPeers() - { - LoadModalities(); - LoadPeers(); - } - - - void OrthancConfiguration::GetDicomModalityUsingSymbolicName( - RemoteModalityParameters& modality, - const std::string& name) const - { - Modalities::const_iterator found = modalities_.find(name); - - if (found == modalities_.end()) - { - throw OrthancException(ErrorCode_InexistentItem, - "No modality with symbolic name: " + name); - } - else - { - modality = found->second; - } - } - - - bool OrthancConfiguration::LookupOrthancPeer(WebServiceParameters& peer, - const std::string& name) const - { - Peers::const_iterator found = peers_.find(name); - - if (found == peers_.end()) - { - LOG(ERROR) << "No peer with symbolic name: " << name; - return false; - } - else - { - peer = found->second; - return true; - } - } - - - void OrthancConfiguration::GetListOfDicomModalities(std::set& target) const - { - target.clear(); - - for (Modalities::const_iterator - it = modalities_.begin(); it != modalities_.end(); ++it) - { - target.insert(it->first); - } - } - - - void OrthancConfiguration::GetListOfOrthancPeers(std::set& target) const - { - target.clear(); - - for (Peers::const_iterator it = peers_.begin(); it != peers_.end(); ++it) - { - target.insert(it->first); - } - } - - - bool OrthancConfiguration::SetupRegisteredUsers(HttpServer& httpServer) const - { - httpServer.ClearUsers(); - - if (!json_.isMember("RegisteredUsers")) - { - return false; - } - - const Json::Value& users = json_["RegisteredUsers"]; - if (users.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, "Badly formatted list of users"); - } - - bool hasUser = false; - Json::Value::Members usernames = users.getMemberNames(); - for (size_t i = 0; i < usernames.size(); i++) - { - const std::string& username = usernames[i]; - std::string password = users[username].asString(); - httpServer.RegisterUser(username.c_str(), password.c_str()); - hasUser = true; - } - - return hasUser; - } - - - std::string OrthancConfiguration::InterpretStringParameterAsPath( - const std::string& parameter) const - { - return SystemToolbox::InterpretRelativePath(defaultDirectory_.string(), parameter); - } - - - void OrthancConfiguration::GetListOfStringsParameter(std::list& target, - const std::string& key) const - { - target.clear(); - - if (!json_.isMember(key)) - { - return; - } - - const Json::Value& lst = json_[key]; - - if (lst.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat, "Badly formatted list of strings"); - } - - for (Json::Value::ArrayIndex i = 0; i < lst.size(); i++) - { - target.push_back(lst[i].asString()); - } - } - - - bool OrthancConfiguration::IsSameAETitle(const std::string& aet1, - const std::string& aet2) const - { - if (GetBooleanParameter("StrictAetComparison", false)) - { - // Case-sensitive matching - return aet1 == aet2; - } - else - { - // Case-insensitive matching (default) - std::string tmp1, tmp2; - Toolbox::ToLowerCase(tmp1, aet1); - Toolbox::ToLowerCase(tmp2, aet2); - return tmp1 == tmp2; - } - } - - - bool OrthancConfiguration::LookupDicomModalityUsingAETitle(RemoteModalityParameters& modality, - const std::string& aet) const - { - for (Modalities::const_iterator it = modalities_.begin(); it != modalities_.end(); ++it) - { - if (IsSameAETitle(aet, it->second.GetApplicationEntityTitle())) - { - modality = it->second; - return true; - } - } - - return false; - } - - - bool OrthancConfiguration::IsKnownAETitle(const std::string& aet, - const std::string& ip) const - { - RemoteModalityParameters modality; - - if (!LookupDicomModalityUsingAETitle(modality, aet)) - { - LOG(WARNING) << "Modality \"" << aet - << "\" is not listed in the \"DicomModalities\" configuration option"; - return false; - } - else if (!GetBooleanParameter("DicomCheckModalityHost", false) || - ip == modality.GetHost()) - { - return true; - } - else - { - LOG(WARNING) << "Forbidding access from AET \"" << aet - << "\" given its hostname (" << ip << ") does not match " - << "the \"DicomModalities\" configuration option (" - << modality.GetHost() << " was expected)"; - return false; - } - } - - - RemoteModalityParameters - OrthancConfiguration::GetModalityUsingSymbolicName(const std::string& name) const - { - RemoteModalityParameters modality; - GetDicomModalityUsingSymbolicName(modality, name); - - return modality; - } - - - RemoteModalityParameters - OrthancConfiguration::GetModalityUsingAet(const std::string& aet) const - { - RemoteModalityParameters modality; - - if (LookupDicomModalityUsingAETitle(modality, aet)) - { - return modality; - } - else - { - throw OrthancException(ErrorCode_InexistentItem, - "Unknown modality for AET: " + aet); - } - } - - - void OrthancConfiguration::UpdateModality(const std::string& symbolicName, - const RemoteModalityParameters& modality) - { - CheckAlphanumeric(symbolicName); - - modalities_[symbolicName] = modality; - SaveModalities(); - } - - - void OrthancConfiguration::RemoveModality(const std::string& symbolicName) - { - modalities_.erase(symbolicName); - SaveModalities(); - } - - - void OrthancConfiguration::UpdatePeer(const std::string& symbolicName, - const WebServiceParameters& peer) - { - CheckAlphanumeric(symbolicName); - - peer.CheckClientCertificate(); - - peers_[symbolicName] = peer; - SavePeers(); - } - - - void OrthancConfiguration::RemovePeer(const std::string& symbolicName) - { - peers_.erase(symbolicName); - SavePeers(); - } - - - void OrthancConfiguration::Format(std::string& result) const - { - Json::StyledWriter w; - result = w.write(json_); - } - - - void OrthancConfiguration::SetDefaultEncoding(Encoding encoding) - { - SetDefaultDicomEncoding(encoding); - - // Propagate the encoding to the configuration file that is - // stored in memory - json_["DefaultEncoding"] = EnumerationToString(encoding); - } - - - bool OrthancConfiguration::HasConfigurationChanged() const - { - Json::Value current; - ReadConfiguration(current, configurationFileArg_); - - Json::FastWriter writer; - std::string a = writer.write(json_); - std::string b = writer.write(current); - - return a != b; - } - - - void OrthancConfiguration::SetServerIndex(ServerIndex& index) - { - serverIndex_ = &index; - } - - - void OrthancConfiguration::ResetServerIndex() - { - serverIndex_ = NULL; - } - - - TemporaryFile* OrthancConfiguration::CreateTemporaryFile() const - { - if (json_.isMember(TEMPORARY_DIRECTORY)) - { - return new TemporaryFile(InterpretStringParameterAsPath(GetStringParameter(TEMPORARY_DIRECTORY, ".")), ""); - } - else - { - return new TemporaryFile; - } - } - - - std::string OrthancConfiguration::GetDefaultPrivateCreator() const - { - // New configuration option in Orthanc 1.6.0 - return GetStringParameter("DefaultPrivateCreator", ""); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancConfiguration.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,240 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/Images/FontRegistry.h" -#include "../Core/WebServiceParameters.h" -#include "../Core/DicomNetworking/RemoteModalityParameters.h" - -#include - -#include -#include -#include - -namespace Orthanc -{ - class HttpServer; - class ServerIndex; - class TemporaryFile; - - class OrthancConfiguration : public boost::noncopyable - { - private: - typedef std::map Modalities; - typedef std::map Peers; - - boost::shared_mutex mutex_; - Json::Value json_; - boost::filesystem::path defaultDirectory_; - std::string configurationAbsolutePath_; - FontRegistry fontRegistry_; - const char* configurationFileArg_; - Modalities modalities_; - Peers peers_; - ServerIndex* serverIndex_; - - OrthancConfiguration() : - configurationFileArg_(NULL) - { - } - - void LoadModalitiesFromJson(const Json::Value& source); - - void LoadPeersFromJson(const Json::Value& source); - - void LoadModalities(); - - void LoadPeers(); - - void SaveModalitiesToJson(Json::Value& target); - - void SavePeersToJson(Json::Value& target); - - void SaveModalities(); - - void SavePeers(); - - static OrthancConfiguration& GetInstance(); - - public: - class ReaderLock : public boost::noncopyable - { - private: - OrthancConfiguration& configuration_; - boost::shared_lock lock_; - - public: - ReaderLock() : - configuration_(GetInstance()), - lock_(configuration_.mutex_) - { - } - - const OrthancConfiguration& GetConfiguration() const - { - return configuration_; - } - - const Json::Value& GetJson() const - { - return configuration_.json_; - } - }; - - - class WriterLock : public boost::noncopyable - { - private: - OrthancConfiguration& configuration_; - boost::unique_lock lock_; - - public: - WriterLock() : - configuration_(GetInstance()), - lock_(configuration_.mutex_) - { - } - - OrthancConfiguration& GetConfiguration() - { - return configuration_; - } - - const OrthancConfiguration& GetConfiguration() const - { - return configuration_; - } - - const Json::Value& GetJson() const - { - return configuration_.json_; - } - }; - - - const std::string& GetConfigurationAbsolutePath() const - { - return configurationAbsolutePath_; - } - - const FontRegistry& GetFontRegistry() const - { - return fontRegistry_; - } - - void Read(const char* configurationFile); - - void LoadModalitiesAndPeers(); - - void RegisterFont(EmbeddedResources::FileResourceId resource) - { - fontRegistry_.AddFromResource(resource); - } - - bool LookupStringParameter(std::string& target, - const std::string& parameter) const; - - std::string GetStringParameter(const std::string& parameter, - const std::string& defaultValue) const; - - int GetIntegerParameter(const std::string& parameter, - int defaultValue) const; - - unsigned int GetUnsignedIntegerParameter(const std::string& parameter, - unsigned int defaultValue) const; - - bool LookupBooleanParameter(bool& target, - const std::string& parameter) const; - - bool GetBooleanParameter(const std::string& parameter, - bool defaultValue) const; - - void GetDicomModalityUsingSymbolicName(RemoteModalityParameters& modality, - const std::string& name) const; - - bool LookupOrthancPeer(WebServiceParameters& peer, - const std::string& name) const; - - void GetListOfDicomModalities(std::set& target) const; - - void GetListOfOrthancPeers(std::set& target) const; - - // Returns "true" iff. at least one user is registered - bool SetupRegisteredUsers(HttpServer& httpServer) const; - - std::string InterpretStringParameterAsPath(const std::string& parameter) const; - - void GetListOfStringsParameter(std::list& target, - const std::string& key) const; - - bool IsSameAETitle(const std::string& aet1, - const std::string& aet2) const; - - bool LookupDicomModalityUsingAETitle(RemoteModalityParameters& modality, - const std::string& aet) const; - - bool IsKnownAETitle(const std::string& aet, - const std::string& ip) const; - - RemoteModalityParameters GetModalityUsingSymbolicName(const std::string& name) const; - - RemoteModalityParameters GetModalityUsingAet(const std::string& aet) const; - - void UpdateModality(const std::string& symbolicName, - const RemoteModalityParameters& modality); - - void RemoveModality(const std::string& symbolicName); - - void UpdatePeer(const std::string& symbolicName, - const WebServiceParameters& peer); - - void RemovePeer(const std::string& symbolicName); - - - void Format(std::string& result) const; - - void SetDefaultEncoding(Encoding encoding); - - bool HasConfigurationChanged() const; - - void SetServerIndex(ServerIndex& index); - - void ResetServerIndex(); - - TemporaryFile* CreateTemporaryFile() const; - - std::string GetDefaultPrivateCreator() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,696 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "OrthancFindRequestHandler.h" - -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/Logging.h" -#include "../Core/Lua/LuaFunctionCall.h" -#include "../Core/MetricsRegistry.h" -#include "OrthancConfiguration.h" -#include "Search/DatabaseLookup.h" -#include "ServerContext.h" -#include "ServerToolbox.h" - -#include - - -namespace Orthanc -{ - static void GetChildren(std::list& target, - ServerIndex& index, - const std::list& source) - { - target.clear(); - - for (std::list::const_iterator - it = source.begin(); it != source.end(); ++it) - { - std::list tmp; - index.GetChildren(tmp, *it); - target.splice(target.end(), tmp); - } - } - - - static void StoreSetOfStrings(DicomMap& result, - const DicomTag& tag, - const std::set& values) - { - bool isFirst = true; - - std::string s; - for (std::set::const_iterator - it = values.begin(); it != values.end(); ++it) - { - if (isFirst) - { - isFirst = false; - } - else - { - s += "\\"; - } - - s += *it; - } - - result.SetValue(tag, s, false); - } - - - static void ComputePatientCounters(DicomMap& result, - ServerIndex& index, - const std::string& patient, - const DicomMap& query) - { - std::list studies; - index.GetChildren(studies, patient); - - if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES)) - { - result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES, - boost::lexical_cast(studies.size()), false); - } - - if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) && - !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES)) - { - return; - } - - std::list series; - GetChildren(series, index, studies); - studies.clear(); // This information is useless below - - if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES)) - { - result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES, - boost::lexical_cast(series.size()), false); - } - - if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES)) - { - return; - } - - std::list instances; - GetChildren(instances, index, series); - - if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES)) - { - result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES, - boost::lexical_cast(instances.size()), false); - } - } - - - static void ComputeStudyCounters(DicomMap& result, - ServerContext& context, - const std::string& study, - const DicomMap& query) - { - ServerIndex& index = context.GetIndex(); - - std::list series; - index.GetChildren(series, study); - - if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES)) - { - result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES, - boost::lexical_cast(series.size()), false); - } - - if (query.HasTag(DICOM_TAG_MODALITIES_IN_STUDY)) - { - std::set values; - - for (std::list::const_iterator - it = series.begin(); it != series.end(); ++it) - { - DicomMap tags; - if (index.GetMainDicomTags(tags, *it, ResourceType_Series, ResourceType_Series)) - { - const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - values.insert(value->GetContent()); - } - } - } - - StoreSetOfStrings(result, DICOM_TAG_MODALITIES_IN_STUDY, values); - } - - if (!query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) && - !query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY)) - { - return; - } - - std::list instances; - GetChildren(instances, index, series); - - if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES)) - { - result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, - boost::lexical_cast(instances.size()), false); - } - - if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY)) - { - std::set values; - - for (std::list::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - std::string value; - if (context.LookupOrReconstructMetadata(value, *it, MetadataType_Instance_SopClassUid)) - { - values.insert(value); - } - } - - StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values); - } - } - - - static void ComputeSeriesCounters(DicomMap& result, - ServerIndex& index, - const std::string& series, - const DicomMap& query) - { - std::list instances; - index.GetChildren(instances, series); - - if (query.HasTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES)) - { - result.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, - boost::lexical_cast(instances.size()), false); - } - } - - - static DicomMap* ComputeCounters(ServerContext& context, - const std::string& instanceId, - ResourceType level, - const DicomMap& query) - { - switch (level) - { - case ResourceType_Patient: - if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) && - !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) && - !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES)) - { - return NULL; - } - - break; - - case ResourceType_Study: - if (!query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) && - !query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) && - !query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY) && - !query.HasTag(DICOM_TAG_MODALITIES_IN_STUDY)) - { - return NULL; - } - - break; - - case ResourceType_Series: - if (!query.HasTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES)) - { - return NULL; - } - - break; - - default: - return NULL; - } - - std::string parent; - if (!context.GetIndex().LookupParent(parent, instanceId, level)) - { - throw OrthancException(ErrorCode_UnknownResource); // The resource was deleted in between - } - - std::unique_ptr result(new DicomMap); - - switch (level) - { - case ResourceType_Patient: - ComputePatientCounters(*result, context.GetIndex(), parent, query); - break; - - case ResourceType_Study: - ComputeStudyCounters(*result, context, parent, query); - break; - - case ResourceType_Series: - ComputeSeriesCounters(*result, context.GetIndex(), parent, query); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - return result.release(); - } - - - static void AddAnswer(DicomFindAnswers& answers, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson, - const DicomArray& query, - const std::list& sequencesToReturn, - const DicomMap* counters) - { - DicomMap match; - - if (dicomAsJson != NULL) - { - match.FromDicomAsJson(*dicomAsJson); - } - else - { - match.Assign(mainDicomTags); - } - - DicomMap result; - - for (size_t i = 0; i < query.GetSize(); i++) - { - if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL) - { - // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052)) - result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue()); - } - else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - // Do not include the encoding, this is handled by class ParsedDicomFile - } - else - { - const DicomTag& tag = query.GetElement(i).GetTag(); - const DicomValue* value = match.TestAndGetValue(tag); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - result.SetValue(tag, value->GetContent(), false); - } - else - { - result.SetValue(tag, "", false); - } - } - } - - if (counters != NULL) - { - DicomArray tmp(*counters); - for (size_t i = 0; i < tmp.GetSize(); i++) - { - result.SetValue(tmp.GetElement(i).GetTag(), tmp.GetElement(i).GetValue().GetContent(), false); - } - } - - if (result.GetSize() == 0 && - sequencesToReturn.empty()) - { - LOG(WARNING) << "The C-FIND request does not return any DICOM tag"; - } - else if (sequencesToReturn.empty()) - { - answers.Add(result); - } - else if (dicomAsJson == NULL) - { - LOG(WARNING) << "C-FIND query requesting a sequence, but reading JSON from disk is disabled"; - answers.Add(result); - } - else - { - ParsedDicomFile dicom(result, GetDefaultDicomEncoding(), true /* be permissive, cf. issue #136 */); - - for (std::list::const_iterator tag = sequencesToReturn.begin(); - tag != sequencesToReturn.end(); ++tag) - { - assert(dicomAsJson != NULL); - const Json::Value& source = (*dicomAsJson) [tag->Format()]; - - if (source.type() == Json::objectValue && - source.isMember("Type") && - source.isMember("Value") && - source["Type"].asString() == "Sequence" && - source["Value"].type() == Json::arrayValue) - { - Json::Value content = Json::arrayValue; - - for (Json::Value::ArrayIndex i = 0; i < source["Value"].size(); i++) - { - Json::Value item; - ServerToolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short); - content.append(item); - } - - dicom.Replace(*tag, content, false, DicomReplaceMode_InsertIfAbsent, - "" /* no private creator */); - } - } - - answers.Add(dicom); - } - } - - - - bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, - ResourceType level, - const DicomTag& tag, - ModalityManufacturer manufacturer) - { - // Whatever the manufacturer, remove the GenericGroupLength tags - // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.2.html - // https://bitbucket.org/sjodogne/orthanc/issues/31/ - if (tag.GetElement() == 0x0000) - { - return false; - } - - switch (manufacturer) - { - case ModalityManufacturer_Vitrea: - // Following Denis Nesterov's mail on 2015-11-30 - if (tag == DicomTag(0x5653, 0x0010)) // "PrivateCreator = Vital Images SW 3.4" - { - return false; - } - - break; - - default: - break; - } - - return true; - } - - - bool OrthancFindRequestHandler::ApplyLuaFilter(DicomMap& target, - const DicomMap& source, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer) - { - static const char* LUA_CALLBACK = "IncomingFindRequestFilter"; - - LuaScripting::Lock lock(context_.GetLuaScripting()); - - if (!lock.GetLua().IsExistingFunction(LUA_CALLBACK)) - { - return false; - } - else - { - Json::Value origin; - FormatOrigin(origin, remoteIp, remoteAet, calledAet, manufacturer); - - LuaFunctionCall call(lock.GetLua(), LUA_CALLBACK); - call.PushDicom(source); - call.PushJson(origin); - FromDcmtkBridge::ExecuteToDicom(target, call); - - return true; - } - } - - - OrthancFindRequestHandler::OrthancFindRequestHandler(ServerContext& context) : - context_(context), - maxResults_(0), - maxInstances_(0) - { - } - - - class OrthancFindRequestHandler::LookupVisitor : public ServerContext::ILookupVisitor - { - private: - DicomFindAnswers& answers_; - ServerContext& context_; - ResourceType level_; - const DicomMap& query_; - DicomArray queryAsArray_; - const std::list& sequencesToReturn_; - - public: - LookupVisitor(DicomFindAnswers& answers, - ServerContext& context, - ResourceType level, - const DicomMap& query, - const std::list& sequencesToReturn) : - answers_(answers), - context_(context), - level_(level), - query_(query), - queryAsArray_(query), - sequencesToReturn_(sequencesToReturn) - { - answers_.SetComplete(false); - } - - virtual bool IsDicomAsJsonNeeded() const - { - // Ask the "DICOM-as-JSON" attachment only if sequences are to - // be returned OR if "query_" contains non-main DICOM tags! - - DicomMap withoutSpecialTags; - withoutSpecialTags.Assign(query_); - - // Check out "ComputeCounters()" - withoutSpecialTags.Remove(DICOM_TAG_MODALITIES_IN_STUDY); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES); - withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES); - withoutSpecialTags.Remove(DICOM_TAG_SOP_CLASSES_IN_STUDY); - - // Check out "AddAnswer()" - withoutSpecialTags.Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET); - withoutSpecialTags.Remove(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - - return (!sequencesToReturn_.empty() || - !withoutSpecialTags.HasOnlyMainDicomTags()); - } - - virtual void MarkAsComplete() - { - answers_.SetComplete(true); - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) - { - std::unique_ptr counters(ComputeCounters(context_, instanceId, level_, query_)); - - AddAnswer(answers_, mainDicomTags, dicomAsJson, - queryAsArray_, sequencesToReturn_, counters.get()); - } - }; - - - void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, - const DicomMap& input, - const std::list& sequencesToReturn, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer) - { - MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_find_scp_duration_ms"); - - /** - * Possibly apply the user-supplied Lua filter. - **/ - - DicomMap lua; - const DicomMap* filteredInput = &input; - - if (ApplyLuaFilter(lua, input, remoteIp, remoteAet, calledAet, manufacturer)) - { - filteredInput = &lua; - } - - - /** - * Retrieve the query level. - **/ - - assert(filteredInput != NULL); - const DicomValue* levelTmp = filteredInput->TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - if (levelTmp == NULL || - levelTmp->IsNull() || - levelTmp->IsBinary()) - { - throw OrthancException(ErrorCode_BadRequest, - "C-FIND request without the tag 0008,0052 (QueryRetrieveLevel)"); - } - - ResourceType level = StringToResourceType(levelTmp->GetContent().c_str()); - - if (level != ResourceType_Patient && - level != ResourceType_Study && - level != ResourceType_Series && - level != ResourceType_Instance) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - - DicomArray query(*filteredInput); - LOG(INFO) << "DICOM C-Find request at level: " << EnumerationToString(level); - - for (size_t i = 0; i < query.GetSize(); i++) - { - if (!query.GetElement(i).GetValue().IsNull()) - { - LOG(INFO) << " " << query.GetElement(i).GetTag() - << " " << FromDcmtkBridge::GetTagName(query.GetElement(i)) - << " = " << query.GetElement(i).GetValue().GetContent(); - } - } - - for (std::list::const_iterator it = sequencesToReturn.begin(); - it != sequencesToReturn.end(); ++it) - { - LOG(INFO) << " (" << it->Format() - << ") " << FromDcmtkBridge::GetTagName(*it, "") - << " : sequence tag whose content will be copied"; - } - - - /** - * Build up the query object. - **/ - - DatabaseLookup lookup; - - bool caseSensitivePN; - - { - OrthancConfiguration::ReaderLock lock; - caseSensitivePN = lock.GetConfiguration().GetBooleanParameter("CaseSensitivePN", false); - } - - for (size_t i = 0; i < query.GetSize(); i++) - { - const DicomElement& element = query.GetElement(i); - const DicomTag tag = element.GetTag(); - - if (element.GetValue().IsNull() || - tag == DICOM_TAG_QUERY_RETRIEVE_LEVEL || - tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - continue; - } - - std::string value = element.GetValue().GetContent(); - if (value.size() == 0) - { - // An empty string corresponds to an universal constraint, so we ignore it - continue; - } - - if (FilterQueryTag(value, level, tag, manufacturer)) - { - ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(tag); - - // DICOM specifies that searches must be case sensitive, except - // for tags with a PN value representation - bool sensitive = true; - if (vr == ValueRepresentation_PersonName) - { - sensitive = caseSensitivePN; - } - - lookup.AddDicomConstraint(tag, value, sensitive, true /* mandatory */); - } - else - { - LOG(INFO) << "Because of a patch for the manufacturer of the remote modality, " - << "ignoring constraint on tag (" << tag.Format() << ") " << FromDcmtkBridge::GetTagName(element); - } - } - - - /** - * Run the query. - **/ - - size_t limit = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; - - - LookupVisitor visitor(answers, context_, level, *filteredInput, sequencesToReturn); - context_.Apply(visitor, lookup, level, 0 /* "since" is not relevant to C-FIND */, limit); - } - - - void OrthancFindRequestHandler::FormatOrigin(Json::Value& origin, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer) - { - origin = Json::objectValue; - origin["RemoteIp"] = remoteIp; - origin["RemoteAet"] = remoteAet; - origin["CalledAet"] = calledAet; - origin["Manufacturer"] = EnumerationToString(manufacturer); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancFindRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include "../Core/DicomNetworking/IFindRequestHandler.h" - -namespace Orthanc -{ - class ServerContext; - - class OrthancFindRequestHandler : public IFindRequestHandler - { - private: - class LookupVisitor; - - ServerContext& context_; - unsigned int maxResults_; - unsigned int maxInstances_; - - bool HasReachedLimit(const DicomFindAnswers& answers, - ResourceType level) const; - - bool FilterQueryTag(std::string& value /* can be modified */, - ResourceType level, - const DicomTag& tag, - ModalityManufacturer manufacturer); - - bool ApplyLuaFilter(DicomMap& target, - const DicomMap& source, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer); - - public: - OrthancFindRequestHandler(ServerContext& context); - - virtual void Handle(DicomFindAnswers& answers, - const DicomMap& input, - const std::list& sequencesToReturn, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer); - - unsigned int GetMaxResults() const - { - return maxResults_; - } - - void SetMaxResults(unsigned int results) - { - maxResults_ = results; - } - - unsigned int GetMaxInstances() const - { - return maxInstances_; - } - - void SetMaxInstances(unsigned int instances) - { - maxInstances_ = instances; - } - - static void FormatOrigin(Json::Value& origin, - const std::string& remoteIp, - const std::string& remoteAet, - const std::string& calledAet, - ModalityManufacturer manufacturer); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,583 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#include "PrecompiledHeadersServer.h" -#include "OrthancGetRequestHandler.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/Logging.h" -#include "../Core/MetricsRegistry.h" -#include "OrthancConfiguration.h" -#include "ServerContext.h" -#include "ServerJobs/DicomModalityStoreJob.h" - -#include -#include -#include -#include -#include -#include -#include - -#include // For std::stringstream - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - - static void GetSubOpProgressCallback( - void * /* callbackData == pointer to the "OrthancGetRequestHandler" object */, - T_DIMSE_StoreProgress *progress, - T_DIMSE_C_StoreRQ * /*req*/) - { - // SBL - no logging to be done here. - } - } - - OrthancGetRequestHandler::Status - OrthancGetRequestHandler::DoNext(T_ASC_Association* assoc) - { - if (position_ >= instances_.size()) - { - return Status_Failure; - } - - const std::string& id = instances_[position_++]; - - std::string dicom; - context_.ReadDicom(dicom, id); - - if (dicom.size() <= 0) - { - return Status_Failure; - } - - std::unique_ptr parsed( - FromDcmtkBridge::LoadFromMemoryBuffer(dicom.c_str(), dicom.size())); - - if (parsed.get() == NULL || - parsed->getDataset() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DcmDataset& dataset = *parsed->getDataset(); - - OFString a, b; - if (!dataset.findAndGetOFString(DCM_SOPClassUID, a).good() || - !dataset.findAndGetOFString(DCM_SOPInstanceUID, b).good()) - { - throw OrthancException(ErrorCode_NoSopClassOrInstance, - "Unable to determine the SOP class/instance for C-STORE with AET " + - originatorAet_); - } - - std::string sopClassUid(a.c_str()); - std::string sopInstanceUid(b.c_str()); - - OFCondition cond = PerformGetSubOp(assoc, sopClassUid, sopInstanceUid, parsed.release()); - - if (getCancelled_) - { - LOG(INFO) << "C-GET SCP: Received C-Cancel RQ"; - } - - if (cond.bad() || getCancelled_) - { - return Status_Failure; - } - - return Status_Success; - } - - - void OrthancGetRequestHandler::AddFailedUIDInstance(const std::string& sopInstance) - { - if (failedUIDs_.empty()) - { - failedUIDs_ = sopInstance; - } - else - { - failedUIDs_ += "\\" + sopInstance; - } - } - - - static bool SelectPresentationContext(T_ASC_PresentationContextID& selectedPresentationId, - DicomTransferSyntax& selectedSyntax, - T_ASC_Association* assoc, - const std::string& sopClassUid, - DicomTransferSyntax sourceSyntax, - bool allowTranscoding) - { - typedef std::map Accepted; - - Accepted accepted; - - /** - * 1. Inspect and index all the accepted transfer syntaxes. This - * is similar to the code from "DicomAssociation::Open()". - **/ - - LST_HEAD **l = &assoc->params->DULparams.acceptedPresentationContext; - if (*l != NULL) - { - DUL_PRESENTATIONCONTEXT* pc = (DUL_PRESENTATIONCONTEXT*) LST_Head(l); - LST_Position(l, (LST_NODE*)pc); - while (pc) - { - DicomTransferSyntax transferSyntax; - if (pc->result == ASC_P_ACCEPTANCE && - LookupTransferSyntax(transferSyntax, pc->acceptedTransferSyntax)) - { - VLOG(0) << "C-GET SCP accepted: SOP class " << sopClassUid - << " with transfer syntax " << GetTransferSyntaxUid(transferSyntax); - if (std::string(pc->abstractSyntax) == sopClassUid) - { - accepted[transferSyntax] = pc->presentationContextID; - } - } - else - { - LOG(WARNING) << "C-GET: Unknown transfer syntax received: " - << pc->acceptedTransferSyntax; - } - - pc = (DUL_PRESENTATIONCONTEXT*) LST_Next(l); - } - } - - - /** - * 2. Select the preferred transfer syntaxes, which corresponds to - * the source transfer syntax, plus all the uncompressed transfer - * syntaxes if transcoding is enabled. - **/ - - std::list preferred; - preferred.push_back(sourceSyntax); - - if (allowTranscoding) - { - if (sourceSyntax != DicomTransferSyntax_LittleEndianImplicit) - { - // Default Transfer Syntax for DICOM - preferred.push_back(DicomTransferSyntax_LittleEndianImplicit); - } - - if (sourceSyntax != DicomTransferSyntax_LittleEndianExplicit) - { - preferred.push_back(DicomTransferSyntax_LittleEndianExplicit); - } - - if (sourceSyntax != DicomTransferSyntax_BigEndianExplicit) - { - // Retired - preferred.push_back(DicomTransferSyntax_BigEndianExplicit); - } - } - - - /** - * 3. Lookup whether one of the preferred transfer syntaxes was - * accepted. - **/ - - for (std::list::const_iterator - it = preferred.begin(); it != preferred.end(); ++it) - { - Accepted::const_iterator found = accepted.find(*it); - if (found != accepted.end()) - { - selectedPresentationId = found->second; - selectedSyntax = *it; - return true; - } - } - - // No preferred syntax was accepted - return false; - } - - - OFCondition OrthancGetRequestHandler::PerformGetSubOp(T_ASC_Association* assoc, - const std::string& sopClassUid, - const std::string& sopInstanceUid, - DcmFileFormat* dicomRaw) - { - assert(dicomRaw != NULL); - std::unique_ptr dicom(dicomRaw); - - DicomTransferSyntax sourceSyntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax(sourceSyntax, *dicom)) - { - nFailed_++; - AddFailedUIDInstance(sopInstanceUid); - LOG(ERROR) << "C-GET SCP: Unknown transfer syntax: (" - << dcmSOPClassUIDToModality(sopClassUid.c_str(), "OT") << ") " << sopClassUid; - return DIMSE_NOVALIDPRESENTATIONCONTEXTID; - } - - bool allowTranscoding = (context_.IsTranscodeDicomProtocol() && - remote_.IsTranscodingAllowed()); - - T_ASC_PresentationContextID presId; - DicomTransferSyntax selectedSyntax; - if (!SelectPresentationContext(presId, selectedSyntax, assoc, sopClassUid, - sourceSyntax, allowTranscoding) || - presId == 0) - { - nFailed_++; - AddFailedUIDInstance(sopInstanceUid); - LOG(ERROR) << "C-GET SCP: storeSCU: No presentation context for: (" - << dcmSOPClassUIDToModality(sopClassUid.c_str(), "OT") << ") " << sopClassUid; - return DIMSE_NOVALIDPRESENTATIONCONTEXTID; - } - else - { - LOG(INFO) << "C-GET SCP selected transfer syntax " << GetTransferSyntaxUid(selectedSyntax) - << ", for source instance with SOP class " << sopClassUid - << " and transfer syntax " << GetTransferSyntaxUid(sourceSyntax); - - // make sure that we can send images in this presentation context - T_ASC_PresentationContext pc; - ASC_findAcceptedPresentationContext(assoc->params, presId, &pc); - // the acceptedRole is the association requestor role - - if (pc.acceptedRole != ASC_SC_ROLE_DEFAULT && // "DEFAULT" is necessary for GinkgoCADx - pc.acceptedRole != ASC_SC_ROLE_SCP && - pc.acceptedRole != ASC_SC_ROLE_SCUSCP) - { - // the role is not appropriate - nFailed_++; - AddFailedUIDInstance(sopInstanceUid); - LOG(ERROR) << "C-GET SCP: storeSCU: [No presentation context with requestor SCP role for: (" - << dcmSOPClassUIDToModality(sopClassUid.c_str(), "OT") << ") " << sopClassUid; - return DIMSE_NOVALIDPRESENTATIONCONTEXTID; - } - } - - const DIC_US msgId = assoc->nextMsgID++; - - T_DIMSE_C_StoreRQ req; - memset(&req, 0, sizeof(req)); - req.MessageID = msgId; - strncpy(req.AffectedSOPClassUID, sopClassUid.c_str(), DIC_UI_LEN); - strncpy(req.AffectedSOPInstanceUID, sopInstanceUid.c_str(), DIC_UI_LEN); - req.DataSetType = DIMSE_DATASET_PRESENT; - req.Priority = DIMSE_PRIORITY_MEDIUM; - req.opts = 0; - - T_DIMSE_C_StoreRSP rsp; - memset(&rsp, 0, sizeof(rsp)); - - LOG(INFO) << "Store SCU RQ: MsgID " << msgId << ", (" - << dcmSOPClassUIDToModality(sopClassUid.c_str(), "OT") << ")"; - - T_DIMSE_DetectedCancelParameters cancelParameters; - memset(&cancelParameters, 0, sizeof(cancelParameters)); - - std::unique_ptr stDetail; - - OFCondition cond; - - if (sourceSyntax == selectedSyntax) - { - // No transcoding is required - DcmDataset *stDetailTmp = NULL; - cond = DIMSE_storeUser( - assoc, presId, &req, NULL /* imageFileName */, dicom->getDataset(), - GetSubOpProgressCallback, this /* callbackData */, - (timeout_ > 0 ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), timeout_, - &rsp, &stDetailTmp, &cancelParameters); - stDetail.reset(stDetailTmp); - } - else - { - // Transcoding to the selected uncompressed transfer syntax - IDicomTranscoder::DicomImage source, transcoded; - source.AcquireParsed(dicom.release()); - - std::set ts; - ts.insert(selectedSyntax); - - if (context_.Transcode(transcoded, source, ts, true)) - { - // Transcoding has succeeded - DcmDataset *stDetailTmp = NULL; - cond = DIMSE_storeUser( - assoc, presId, &req, NULL /* imageFileName */, - transcoded.GetParsed().getDataset(), - GetSubOpProgressCallback, this /* callbackData */, - (timeout_ > 0 ? DIMSE_NONBLOCKING : DIMSE_BLOCKING), timeout_, - &rsp, &stDetailTmp, &cancelParameters); - stDetail.reset(stDetailTmp); - } - else - { - // Cannot transcode - nFailed_++; - AddFailedUIDInstance(sopInstanceUid); - LOG(ERROR) << "C-GET SCP: Cannot transcode " << sopClassUid - << " from transfer syntax " << GetTransferSyntaxUid(sourceSyntax) - << " to " << GetTransferSyntaxUid(selectedSyntax); - return DIMSE_NOVALIDPRESENTATIONCONTEXTID; - } - } - - if (cond.good()) - { - if (cancelParameters.cancelEncountered) - { - if (origPresId_ == cancelParameters.presId && - origMsgId_ == cancelParameters.req.MessageIDBeingRespondedTo) - { - getCancelled_ = OFTrue; - } - else - { - LOG(ERROR) << "C-GET SCP: Unexpected C-Cancel-RQ encountered: pid=" << (int)cancelParameters.presId - << ", mid=" << (int)cancelParameters.req.MessageIDBeingRespondedTo; - } - } - - if (rsp.DimseStatus == STATUS_Success) - { - // everything ok - nCompleted_++; - } - else if ((rsp.DimseStatus & 0xf000) == 0xb000) - { - // a warning status message - warningCount_++; - LOG(ERROR) << "C-GET SCP: Store Warning: Response Status: " - << DU_cstoreStatusString(rsp.DimseStatus); - } - else - { - nFailed_++; - AddFailedUIDInstance(sopInstanceUid); - // print a status message - LOG(ERROR) << "C-GET SCP: Store Failed: Response Status: " - << DU_cstoreStatusString(rsp.DimseStatus); - } - } - else - { - nFailed_++; - AddFailedUIDInstance(sopInstanceUid); - OFString temp_str; - LOG(ERROR) << "C-GET SCP: storeSCU: Store Request Failed: " << DimseCondition::dump(temp_str, cond); - } - - if (stDetail.get() != NULL) - { - // It is impossible to directly use the "<<" stream construct - // with "DcmObject::PrintHelper" using MSVC2008 - std::stringstream s; - DcmObject::PrintHelper obj(*stDetail); - obj.dcmobj_.print(s); - - LOG(INFO) << " Status Detail: " << s.str(); - } - - return cond; - } - - bool OrthancGetRequestHandler::LookupIdentifiers(std::list& publicIds, - ResourceType level, - const DicomMap& input) const - { - DicomTag tag(0, 0); // Dummy initialization - - switch (level) - { - case ResourceType_Patient: - tag = DICOM_TAG_PATIENT_ID; - break; - - case ResourceType_Study: - tag = (input.HasTag(DICOM_TAG_ACCESSION_NUMBER) ? - DICOM_TAG_ACCESSION_NUMBER : DICOM_TAG_STUDY_INSTANCE_UID); - break; - - case ResourceType_Series: - tag = DICOM_TAG_SERIES_INSTANCE_UID; - break; - - case ResourceType_Instance: - tag = DICOM_TAG_SOP_INSTANCE_UID; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (!input.HasTag(tag)) - { - return false; - } - - const DicomValue& value = input.GetValue(tag); - if (value.IsNull() || - value.IsBinary()) - { - return false; - } - else - { - std::vector tokens; - Toolbox::TokenizeString(tokens, value.GetContent(), '\\'); - - for (size_t i = 0; i < tokens.size(); i++) - { - std::vector tmp; - context_.GetIndex().LookupIdentifierExact(tmp, level, tag, tokens[i]); - - if (tmp.empty()) - { - LOG(ERROR) << "C-GET: Cannot locate resource \"" << tokens[i] - << "\" at the " << EnumerationToString(level) << " level"; - return false; - } - else - { - for (size_t i = 0; i < tmp.size(); i++) - { - publicIds.push_back(tmp[i]); - } - } - } - - return true; - } - } - - - OrthancGetRequestHandler::OrthancGetRequestHandler(ServerContext& context) : - context_(context) - { - position_ = 0; - nRemaining_ = 0; - nCompleted_ = 0; - warningCount_ = 0; - nFailed_ = 0; - timeout_ = 0; - } - - - bool OrthancGetRequestHandler::Handle(const DicomMap& input, - const std::string& originatorIp, - const std::string& originatorAet, - const std::string& calledAet, - uint32_t timeout) - { - MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_get_scp_duration_ms"); - - LOG(WARNING) << "C-GET-SCU request received from AET \"" << originatorAet << "\""; - - { - DicomArray query(input); - for (size_t i = 0; i < query.GetSize(); i++) - { - if (!query.GetElement(i).GetValue().IsNull()) - { - LOG(INFO) << " " << query.GetElement(i).GetTag() - << " " << FromDcmtkBridge::GetTagName(query.GetElement(i)) - << " = " << query.GetElement(i).GetValue().GetContent(); - } - } - } - - /** - * Retrieve the query level. - **/ - - const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - - assert(levelTmp != NULL); - ResourceType level = StringToResourceType(levelTmp->GetContent().c_str()); - - - /** - * Lookup for the resource to be sent. - **/ - - std::list publicIds; - - if (!LookupIdentifiers(publicIds, level, input)) - { - LOG(ERROR) << "Cannot determine what resources are requested by C-GET"; - return false; - } - - localAet_ = context_.GetDefaultLocalApplicationEntityTitle(); - position_ = 0; - originatorAet_ = originatorAet; - - { - OrthancConfiguration::ReaderLock lock; - remote_ = lock.GetConfiguration().GetModalityUsingAet(originatorAet); - } - - for (std::list::const_iterator - resource = publicIds.begin(); resource != publicIds.end(); ++resource) - { - LOG(INFO) << "C-GET: Sending resource " << *resource - << " to modality \"" << originatorAet << "\""; - - std::list tmp; - context_.GetIndex().GetChildInstances(tmp, *resource); - - instances_.reserve(tmp.size()); - for (std::list::iterator it = tmp.begin(); it != tmp.end(); ++it) - { - instances_.push_back(*it); - } - } - - failedUIDs_.clear(); - getCancelled_ = OFFalse; - - nRemaining_ = GetSubOperationCount(); - nCompleted_ = 0; - nFailed_ = 0; - warningCount_ = 0; - timeout_ = timeout; - - return true; - } -}; diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancGetRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include "../Core/DicomNetworking/IGetRequestHandler.h" -#include "../Core/DicomNetworking/RemoteModalityParameters.h" - -#include - -#include - -class DcmFileFormat; - -namespace Orthanc -{ - class ServerContext; - - class OrthancGetRequestHandler : public IGetRequestHandler - { - private: - ServerContext& context_; - std::string localAet_; - std::vector instances_; - size_t position_; - RemoteModalityParameters remote_; - std::string originatorAet_; - - unsigned int nRemaining_; - unsigned int nCompleted_; - unsigned int warningCount_; - unsigned int nFailed_; - std::string failedUIDs_; - - DIC_US origMsgId_; - T_ASC_PresentationContextID origPresId_; - - bool getCancelled_; - uint32_t timeout_; - - bool LookupIdentifiers(std::list& publicIds, - ResourceType level, - const DicomMap& input) const; - - OFCondition PerformGetSubOp(T_ASC_Association *assoc, - const std::string& sopClassUid, - const std::string& sopInstanceUid, - DcmFileFormat* datasetRaw); - - void AddFailedUIDInstance(const std::string& sopInstance); - - public: - OrthancGetRequestHandler(ServerContext& context); - - virtual bool Handle(const DicomMap& input, - const std::string& originatorIp, - const std::string& originatorAet, - const std::string& calledAet, - uint32_t timeout) ORTHANC_OVERRIDE; - - virtual Status DoNext(T_ASC_Association *assoc) ORTHANC_OVERRIDE; - - virtual unsigned int GetSubOperationCount() const ORTHANC_OVERRIDE - { - return static_cast(instances_.size()); - } - - virtual unsigned int GetRemainingCount() const ORTHANC_OVERRIDE - { - return nRemaining_; - } - - virtual unsigned int GetCompletedCount() const ORTHANC_OVERRIDE - { - return nCompleted_; - } - - virtual unsigned int GetWarningCount() const ORTHANC_OVERRIDE - { - return warningCount_; - } - - virtual unsigned int GetFailedCount() const ORTHANC_OVERRIDE - { - return nFailed_; - } - - virtual const std::string& GetFailedUids() const ORTHANC_OVERRIDE - { - return failedUIDs_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "OrthancHttpHandler.h" - -#include "../Core/OrthancException.h" - - -namespace Orthanc -{ - bool OrthancHttpHandler::CreateChunkedRequestReader( - std::unique_ptr& target, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers) - { - if (method != HttpMethod_Post && - method != HttpMethod_Put) - { - throw OrthancException(ErrorCode_InternalError); - } - - for (Handlers::const_iterator it = handlers_.begin(); it != handlers_.end(); ++it) - { - if ((*it)->CreateChunkedRequestReader - (target, origin, remoteIp, username, method, uri, headers)) - { - if (target.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - return true; - } - } - - return false; - } - - - bool OrthancHttpHandler::Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize) - { - for (Handlers::const_iterator it = handlers_.begin(); it != handlers_.end(); ++it) - { - if ((*it)->Handle(output, origin, remoteIp, username, method, uri, - headers, getArguments, bodyData, bodySize)) - { - return true; - } - } - - return false; - } - - - void OrthancHttpHandler::Register(IHttpHandler& handler, - bool isOrthancRestApi) - { - handlers_.push_back(&handler); - - if (isOrthancRestApi) - { - orthancRestApi_ = &handler; - } - } - - - IHttpHandler& OrthancHttpHandler::RestrictToOrthancRestApi(bool restrict) - { - if (restrict) - { - if (orthancRestApi_ == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - return *orthancRestApi_; - } - else - { - return *this; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancHttpHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/HttpServer/IHttpHandler.h" - -namespace Orthanc -{ - class OrthancHttpHandler : public IHttpHandler - { - private: - typedef std::list Handlers; - - Handlers handlers_; - IHttpHandler *orthancRestApi_; - - public: - OrthancHttpHandler() : orthancRestApi_(NULL) - { - } - - virtual bool CreateChunkedRequestReader(std::unique_ptr& target, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers); - - virtual bool Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize); - - void Register(IHttpHandler& handler, - bool isOrthancRestApi); - - bool HasOrthancRestApi() const - { - return orthancRestApi_ != NULL; - } - - IHttpHandler& RestrictToOrthancRestApi(bool restrict); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,400 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" - -#if defined(_WIN32) -// "Please include winsock2.h before windows.h" -# include -#endif - -#include "OrthancInitialization.h" - -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/FileStorage/FilesystemStorage.h" -#include "../Core/Logging.h" -#include "../Core/OrthancException.h" - -#include "Database/SQLiteDatabaseWrapper.h" -#include "OrthancConfiguration.h" - -#include // For dcmDisableGethostbyaddr() - - - -namespace Orthanc -{ - static void RegisterUserMetadata(const Json::Value& config) - { - if (config.isMember("UserMetadata")) - { - const Json::Value& parameter = config["UserMetadata"]; - - Json::Value::Members members = parameter.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - - if (!parameter[name].isInt()) - { - throw OrthancException(ErrorCode_BadParameterType, - "Not a number in this user-defined metadata: " + name); - } - - int metadata = parameter[name].asInt(); - - LOG(INFO) << "Registering user-defined metadata: " << name << " (index " - << metadata << ")"; - - try - { - RegisterUserMetadata(metadata, name); - } - catch (OrthancException&) - { - LOG(ERROR) << "Cannot register this user-defined metadata: " << name; - throw; - } - } - } - } - - - static void RegisterUserContentType(const Json::Value& config) - { - if (config.isMember("UserContentType")) - { - const Json::Value& parameter = config["UserContentType"]; - - Json::Value::Members members = parameter.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - std::string mime = MIME_BINARY; - - const Json::Value& value = parameter[name]; - int contentType; - - if (value.isArray() && - value.size() == 2 && - value[0].isInt() && - value[1].isString()) - { - contentType = value[0].asInt(); - mime = value[1].asString(); - } - else if (value.isInt()) - { - contentType = value.asInt(); - } - else - { - throw OrthancException(ErrorCode_BadParameterType, - "Not a number in this user-defined attachment type: " + name); - } - - LOG(INFO) << "Registering user-defined attachment type: " << name << " (index " - << contentType << ") with MIME type \"" << mime << "\""; - - try - { - RegisterUserContentType(contentType, name, mime); - } - catch (OrthancException&) - { - throw; - } - } - } - } - - - static void LoadCustomDictionary(const Json::Value& configuration) - { - if (configuration.type() != Json::objectValue || - !configuration.isMember("Dictionary") || - configuration["Dictionary"].type() != Json::objectValue) - { - return; - } - - Json::Value::Members tags(configuration["Dictionary"].getMemberNames()); - - for (Json::Value::ArrayIndex i = 0; i < tags.size(); i++) - { - const Json::Value& content = configuration["Dictionary"][tags[i]]; - if (content.type() != Json::arrayValue || - content.size() < 2 || - content.size() > 5 || - content[0].type() != Json::stringValue || - content[1].type() != Json::stringValue || - (content.size() >= 3 && content[2].type() != Json::intValue) || - (content.size() >= 4 && content[3].type() != Json::intValue) || - (content.size() >= 5 && content[4].type() != Json::stringValue)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - DicomTag tag(FromDcmtkBridge::ParseTag(tags[i])); - ValueRepresentation vr = StringToValueRepresentation(content[0].asString(), true); - std::string name = content[1].asString(); - unsigned int minMultiplicity = (content.size() >= 2) ? content[2].asUInt() : 1; - unsigned int maxMultiplicity = (content.size() >= 3) ? content[3].asUInt() : 1; - std::string privateCreator = (content.size() >= 4) ? content[4].asString() : ""; - - FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity, privateCreator); - } - } - - - static void ConfigurePkcs11(const Json::Value& config) - { - if (config.type() != Json::objectValue || - !config.isMember("Module") || - config["Module"].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "No path to the PKCS#11 module (DLL or .so) is provided " - "for HTTPS client authentication"); - } - - std::string pin; - if (config.isMember("Pin")) - { - if (config["Pin"].type() == Json::stringValue) - { - pin = config["Pin"].asString(); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "The PIN number in the PKCS#11 configuration must be a string"); - } - } - - bool verbose = false; - if (config.isMember("Verbose")) - { - if (config["Verbose"].type() == Json::booleanValue) - { - verbose = config["Verbose"].asBool(); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "The Verbose option in the PKCS#11 configuration must be a Boolean"); - } - } - - HttpClient::InitializePkcs11(config["Module"].asString(), pin, verbose); - } - - - - void OrthancInitialize(const char* configurationFile) - { - OrthancConfiguration::WriterLock lock; - - Toolbox::InitializeOpenSsl(); - - InitializeServerEnumerations(); - - // Read the user-provided configuration - lock.GetConfiguration().Read(configurationFile); - - if (lock.GetJson().isMember("Locale")) - { - std::string locale = lock.GetConfiguration().GetStringParameter("Locale", ""); - Toolbox::InitializeGlobalLocale(lock.GetJson()["Locale"].asCString()); - } - else - { - Toolbox::InitializeGlobalLocale(NULL); - } - - if (lock.GetJson().isMember("DefaultEncoding")) - { - std::string encoding = lock.GetConfiguration().GetStringParameter("DefaultEncoding", ""); - SetDefaultDicomEncoding(StringToEncoding(encoding.c_str())); - } - else - { - SetDefaultDicomEncoding(ORTHANC_DEFAULT_DICOM_ENCODING); - } - - if (lock.GetJson().isMember("Pkcs11")) - { - ConfigurePkcs11(lock.GetJson()["Pkcs11"]); - } - - HttpClient::GlobalInitialize(); - - RegisterUserMetadata(lock.GetJson()); - RegisterUserContentType(lock.GetJson()); - - bool loadPrivate = lock.GetConfiguration().GetBooleanParameter("LoadPrivateDictionary", true); - FromDcmtkBridge::InitializeDictionary(loadPrivate); - LoadCustomDictionary(lock.GetJson()); - - FromDcmtkBridge::InitializeCodecs(); - - lock.GetConfiguration().RegisterFont(EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16); - - /* Disable "gethostbyaddr" (which results in memory leaks) and use raw IP addresses */ - dcmDisableGethostbyaddr.set(OFTrue); - } - - - - void OrthancFinalize() - { - OrthancConfiguration::WriterLock lock; - - HttpClient::GlobalFinalize(); - FromDcmtkBridge::FinalizeCodecs(); - Toolbox::FinalizeOpenSsl(); - Toolbox::FinalizeGlobalLocale(); - } - - - static IDatabaseWrapper* CreateSQLiteWrapper() - { - OrthancConfiguration::ReaderLock lock; - - std::string storageDirectoryStr = - lock.GetConfiguration().GetStringParameter("StorageDirectory", "OrthancStorage"); - - // Open the database - boost::filesystem::path indexDirectory = lock.GetConfiguration().InterpretStringParameterAsPath( - lock.GetConfiguration().GetStringParameter("IndexDirectory", storageDirectoryStr)); - - LOG(WARNING) << "SQLite index directory: " << indexDirectory; - - try - { - boost::filesystem::create_directories(indexDirectory); - } - catch (boost::filesystem::filesystem_error&) - { - } - - return new SQLiteDatabaseWrapper(indexDirectory.string() + "/index"); - } - - - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - - class FilesystemStorageWithoutDicom : public IStorageArea - { - private: - FilesystemStorage storage_; - - public: - FilesystemStorageWithoutDicom(const std::string& path) : storage_(path) - { - } - - virtual void Create(const std::string& uuid, - const void* content, - size_t size, - FileContentType type) - { - if (type != FileContentType_Dicom) - { - storage_.Create(uuid, content, size, type); - } - } - - virtual void Read(std::string& content, - const std::string& uuid, - FileContentType type) - { - if (type != FileContentType_Dicom) - { - storage_.Read(content, uuid, type); - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - virtual void Remove(const std::string& uuid, - FileContentType type) - { - if (type != FileContentType_Dicom) - { - storage_.Remove(uuid, type); - } - } - }; - } - - - static IStorageArea* CreateFilesystemStorage() - { - OrthancConfiguration::ReaderLock lock; - - std::string storageDirectoryStr = - lock.GetConfiguration().GetStringParameter("StorageDirectory", "OrthancStorage"); - - boost::filesystem::path storageDirectory = - lock.GetConfiguration().InterpretStringParameterAsPath(storageDirectoryStr); - - LOG(WARNING) << "Storage directory: " << storageDirectory; - - if (lock.GetConfiguration().GetBooleanParameter("StoreDicom", true)) - { - return new FilesystemStorage(storageDirectory.string()); - } - else - { - LOG(WARNING) << "The DICOM files will not be stored, Orthanc running in index-only mode"; - return new FilesystemStorageWithoutDicom(storageDirectory.string()); - } - } - - - IDatabaseWrapper* CreateDatabaseWrapper() - { - return CreateSQLiteWrapper(); - } - - - IStorageArea* CreateStorageArea() - { - return CreateFilesystemStorage(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancInitialization.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/FileStorage/IStorageArea.h" -#include "Database/IDatabaseWrapper.h" - -namespace Orthanc -{ - void OrthancInitialize(const char* configurationFile = NULL); - - void OrthancFinalize(); - - IDatabaseWrapper* CreateDatabaseWrapper(); - - IStorageArea* CreateStorageArea(); -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,378 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "OrthancMoveRequestHandler.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/Logging.h" -#include "../Core/MetricsRegistry.h" -#include "OrthancConfiguration.h" -#include "ServerContext.h" -#include "ServerJobs/DicomModalityStoreJob.h" - - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - - class SynchronousMove : public IMoveRequestIterator - { - private: - ServerContext& context_; - const std::string& localAet_; - std::vector instances_; - size_t position_; - RemoteModalityParameters remote_; - std::string originatorAet_; - uint16_t originatorId_; - std::unique_ptr connection_; - - public: - SynchronousMove(ServerContext& context, - const std::string& targetAet, - const std::vector& publicIds, - const std::string& originatorAet, - uint16_t originatorId) : - context_(context), - localAet_(context.GetDefaultLocalApplicationEntityTitle()), - position_(0), - originatorAet_(originatorAet), - originatorId_(originatorId) - { - { - OrthancConfiguration::ReaderLock lock; - remote_ = lock.GetConfiguration().GetModalityUsingAet(targetAet); - } - - for (size_t i = 0; i < publicIds.size(); i++) - { - LOG(INFO) << "Sending resource " << publicIds[i] << " to modality \"" - << targetAet << "\" in synchronous mode"; - - std::list tmp; - context_.GetIndex().GetChildInstances(tmp, publicIds[i]); - - instances_.reserve(tmp.size()); - for (std::list::iterator it = tmp.begin(); it != tmp.end(); ++it) - { - instances_.push_back(*it); - } - } - } - - virtual unsigned int GetSubOperationCount() const - { - return instances_.size(); - } - - virtual Status DoNext() - { - if (position_ >= instances_.size()) - { - return Status_Failure; - } - - const std::string& id = instances_[position_++]; - - std::string dicom; - context_.ReadDicom(dicom, id); - - if (connection_.get() == NULL) - { - DicomAssociationParameters params(localAet_, remote_); - connection_.reset(new DicomStoreUserConnection(params)); - } - - std::string sopClassUid, sopInstanceUid; // Unused - - const void* data = dicom.empty() ? NULL : dicom.c_str(); - connection_->Store(sopClassUid, sopInstanceUid, data, dicom.size(), - true, originatorAet_, originatorId_); - - return Status_Success; - } - }; - - - class AsynchronousMove : public IMoveRequestIterator - { - private: - ServerContext& context_; - std::unique_ptr job_; - size_t position_; - size_t countInstances_; - - public: - AsynchronousMove(ServerContext& context, - const std::string& targetAet, - const std::vector& publicIds, - const std::string& originatorAet, - uint16_t originatorId) : - context_(context), - job_(new DicomModalityStoreJob(context)), - position_(0) - { - job_->SetDescription("C-MOVE"); - //job_->SetPermissive(true); // This was the behavior of Orthanc < 1.6.0 - job_->SetPermissive(false); - job_->SetLocalAet(context.GetDefaultLocalApplicationEntityTitle()); - - { - OrthancConfiguration::ReaderLock lock; - job_->SetRemoteModality(lock.GetConfiguration().GetModalityUsingAet(targetAet)); - } - - if (originatorId != 0) - { - job_->SetMoveOriginator(originatorAet, originatorId); - } - - for (size_t i = 0; i < publicIds.size(); i++) - { - LOG(INFO) << "Sending resource " << publicIds[i] << " to modality \"" - << targetAet << "\" in asynchronous mode"; - - std::list tmp; - context_.GetIndex().GetChildInstances(tmp, publicIds[i]); - - countInstances_ = tmp.size(); - - job_->Reserve(job_->GetCommandsCount() + tmp.size()); - - for (std::list::iterator it = tmp.begin(); it != tmp.end(); ++it) - { - job_->AddInstance(*it); - } - } - } - - virtual unsigned int GetSubOperationCount() const - { - return countInstances_; - } - - virtual Status DoNext() - { - if (position_ >= countInstances_) - { - return Status_Failure; - } - - if (position_ == 0) - { - context_.GetJobsEngine().GetRegistry().Submit(job_.release(), 0 /* priority */); - } - - position_ ++; - return Status_Success; - } - }; - } - - - bool OrthancMoveRequestHandler::LookupIdentifiers(std::vector& publicIds, - ResourceType level, - const DicomMap& input) - { - DicomTag tag(0, 0); // Dummy initialization - - switch (level) - { - case ResourceType_Patient: - tag = DICOM_TAG_PATIENT_ID; - break; - - case ResourceType_Study: - tag = (input.HasTag(DICOM_TAG_ACCESSION_NUMBER) ? - DICOM_TAG_ACCESSION_NUMBER : DICOM_TAG_STUDY_INSTANCE_UID); - break; - - case ResourceType_Series: - tag = DICOM_TAG_SERIES_INSTANCE_UID; - break; - - case ResourceType_Instance: - tag = DICOM_TAG_SOP_INSTANCE_UID; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (!input.HasTag(tag)) - { - return false; - } - - const DicomValue& value = input.GetValue(tag); - if (value.IsNull() || - value.IsBinary()) - { - return false; - } - else - { - const std::string& content = value.GetContent(); - - /** - * This tokenization fixes issue 154 ("Matching against list of - * UID-s by C-MOVE"). - * https://bitbucket.org/sjodogne/orthanc/issues/154/ - **/ - - std::vector tokens; - Toolbox::TokenizeString(tokens, content, '\\'); - for (size_t i = 0; i < tokens.size(); i++) - { - std::vector matches; - context_.GetIndex().LookupIdentifierExact(matches, level, tag, tokens[i]); - - // Concatenate "publicIds" with "matches" - publicIds.insert(publicIds.end(), matches.begin(), matches.end()); - } - - return true; - } - } - - - static IMoveRequestIterator* CreateIterator(ServerContext& context, - const std::string& targetAet, - const std::vector& publicIds, - const std::string& originatorAet, - uint16_t originatorId) - { - if (publicIds.empty()) - { - throw OrthancException(ErrorCode_BadRequest, - "C-MOVE request matching no resource stored in Orthanc"); - } - - bool synchronous; - - { - OrthancConfiguration::ReaderLock lock; - synchronous = lock.GetConfiguration().GetBooleanParameter("SynchronousCMove", true); - } - - if (synchronous) - { - return new SynchronousMove(context, targetAet, publicIds, originatorAet, originatorId); - } - else - { - return new AsynchronousMove(context, targetAet, publicIds, originatorAet, originatorId); - } - } - - - IMoveRequestIterator* OrthancMoveRequestHandler::Handle(const std::string& targetAet, - const DicomMap& input, - const std::string& originatorIp, - const std::string& originatorAet, - const std::string& calledAet, - uint16_t originatorId) - { - MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_move_scp_duration_ms"); - - LOG(WARNING) << "Move-SCU request received for AET \"" << targetAet << "\""; - - { - DicomArray query(input); - for (size_t i = 0; i < query.GetSize(); i++) - { - if (!query.GetElement(i).GetValue().IsNull()) - { - LOG(INFO) << " " << query.GetElement(i).GetTag() - << " " << FromDcmtkBridge::GetTagName(query.GetElement(i)) - << " = " << query.GetElement(i).GetValue().GetContent(); - } - } - } - - /** - * Retrieve the query level. - **/ - - const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - - if (levelTmp == NULL || - levelTmp->IsNull() || - levelTmp->IsBinary()) - { - // The query level is not present in the C-Move request, which - // does not follow the DICOM standard. This is for instance the - // behavior of Tudor DICOM. Try and automatically deduce the - // query level: Start from the instance level, going up to the - // patient level until a valid DICOM identifier is found. - - std::vector publicIds; - - if (LookupIdentifiers(publicIds, ResourceType_Instance, input) || - LookupIdentifiers(publicIds, ResourceType_Series, input) || - LookupIdentifiers(publicIds, ResourceType_Study, input) || - LookupIdentifiers(publicIds, ResourceType_Patient, input)) - { - return CreateIterator(context_, targetAet, publicIds, originatorAet, originatorId); - } - else - { - // No identifier is present in the request. - throw OrthancException(ErrorCode_BadRequest, "Invalid fields in a C-MOVE request"); - } - } - - assert(levelTmp != NULL); - ResourceType level = StringToResourceType(levelTmp->GetContent().c_str()); - - - /** - * Lookup for the resource to be sent. - **/ - - std::vector publicIds; - - if (LookupIdentifiers(publicIds, level, input)) - { - return CreateIterator(context_, targetAet, publicIds, originatorAet, originatorId); - } - else - { - throw OrthancException(ErrorCode_BadRequest, "Invalid fields in a C-MOVE request"); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancMoveRequestHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include "../Core/DicomNetworking/IMoveRequestHandler.h" - -namespace Orthanc -{ - class ServerContext; - - class OrthancMoveRequestHandler : public IMoveRequestHandler - { - private: - ServerContext& context_; - - bool LookupIdentifiers(std::vector& publicIds, - ResourceType level, - const DicomMap& input); - - public: - OrthancMoveRequestHandler(ServerContext& context) : - context_(context) - { - } - - virtual IMoveRequestIterator* Handle(const std::string& targetAet, - const DicomMap& input, - const std::string& originatorIp, - const std::string& originatorAet, - const std::string& calledAet, - uint16_t originatorId); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,855 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" -#include "../OrthancConfiguration.h" -#include "../ServerContext.h" -#include "../ServerJobs/MergeStudyJob.h" -#include "../ServerJobs/ResourceModificationJob.h" -#include "../ServerJobs/SplitStudyJob.h" - -#include -#include - -namespace Orthanc -{ - // Modification of DICOM instances ------------------------------------------ - - - static std::string GeneratePatientName(ServerContext& context) - { - uint64_t seq = context.GetIndex().IncrementGlobalSequence(GlobalProperty_AnonymizationSequence); - return "Anonymized" + boost::lexical_cast(seq); - } - - - static void ParseModifyRequest(Json::Value& request, - DicomModification& target, - const RestApiPostCall& call) - { - // curl http://localhost:8042/series/95a6e2bf-9296e2cc-bf614e2f-22b391ee-16e010e0/modify -X POST -d '{"Replace":{"InstitutionName":"My own clinic"},"Priority":9}' - - { - OrthancConfiguration::ReaderLock lock; - target.SetPrivateCreator(lock.GetConfiguration().GetDefaultPrivateCreator()); - } - - if (call.ParseJsonRequest(request)) - { - target.ParseModifyRequest(request); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - static void ParseAnonymizationRequest(Json::Value& request, - DicomModification& target, - RestApiPostCall& call) - { - // curl http://localhost:8042/instances/6e67da51-d119d6ae-c5667437-87b9a8a5-0f07c49f/anonymize -X POST -d '{"Replace":{"PatientName":"hello","0010-0020":"world"},"Keep":["StudyDescription", "SeriesDescription"],"KeepPrivateTags": true,"Remove":["Modality"]}' > Anonymized.dcm - - { - OrthancConfiguration::ReaderLock lock; - target.SetPrivateCreator(lock.GetConfiguration().GetDefaultPrivateCreator()); - } - - if (call.ParseJsonRequest(request) && - request.isObject()) - { - bool patientNameReplaced; - target.ParseAnonymizationRequest(patientNameReplaced, request); - - if (patientNameReplaced) - { - // Overwrite the random Patient's Name by one that is more - // user-friendly (provided none was specified by the user) - target.Replace(DICOM_TAG_PATIENT_NAME, GeneratePatientName(OrthancRestApi::GetContext(call)), true); - } - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - static void AnonymizeOrModifyInstance(DicomModification& modification, - RestApiPostCall& call, - bool transcode, - DicomTransferSyntax targetSyntax) - { - ServerContext& context = OrthancRestApi::GetContext(call); - std::string id = call.GetUriComponent("id", ""); - - std::unique_ptr modified; - - { - ServerContext::DicomCacheLocker locker(context, id); - modified.reset(locker.GetDicom().Clone(true)); - } - - modification.Apply(*modified); - - if (transcode) - { - IDicomTranscoder::DicomImage source; - source.AcquireParsed(*modified); // "modified" is invalid below this point - - IDicomTranscoder::DicomImage transcoded; - - std::set s; - s.insert(targetSyntax); - - if (context.Transcode(transcoded, source, s, true)) - { - call.GetOutput().AnswerBuffer(transcoded.GetBufferData(), - transcoded.GetBufferSize(), MimeType_Dicom); - } - else - { - throw OrthancException(ErrorCode_InternalError, - "Cannot transcode to transfer syntax: " + - std::string(GetTransferSyntaxUid(targetSyntax))); - } - } - else - { - modified->Answer(call.GetOutput()); - } - } - - - static void ModifyInstance(RestApiPostCall& call) - { - DicomModification modification; - modification.SetAllowManualIdentifiers(true); - - Json::Value request; - ParseModifyRequest(request, modification, call); - - if (modification.IsReplaced(DICOM_TAG_PATIENT_ID)) - { - modification.SetLevel(ResourceType_Patient); - } - else if (modification.IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - modification.SetLevel(ResourceType_Study); - } - else if (modification.IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - modification.SetLevel(ResourceType_Series); - } - else - { - modification.SetLevel(ResourceType_Instance); - } - - static const char* TRANSCODE = "Transcode"; - if (request.isMember(TRANSCODE)) - { - std::string s = SerializationToolbox::ReadString(request, TRANSCODE); - - DicomTransferSyntax syntax; - if (LookupTransferSyntax(syntax, s)) - { - AnonymizeOrModifyInstance(modification, call, true, syntax); - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, "Unknown transfer syntax: " + s); - } - } - else - { - AnonymizeOrModifyInstance(modification, call, false /* no transcoding */, - DicomTransferSyntax_LittleEndianImplicit /* unused */); - } - } - - - static void AnonymizeInstance(RestApiPostCall& call) - { - DicomModification modification; - modification.SetAllowManualIdentifiers(true); - - Json::Value request; - ParseAnonymizationRequest(request, modification, call); - - AnonymizeOrModifyInstance(modification, call, false /* no transcoding */, - DicomTransferSyntax_LittleEndianImplicit /* unused */); - } - - - static void SetKeepSource(CleaningInstancesJob& job, - const Json::Value& body) - { - static const char* KEEP_SOURCE = "KeepSource"; - if (body.isMember(KEEP_SOURCE)) - { - job.SetKeepSource(SerializationToolbox::ReadBoolean(body, KEEP_SOURCE)); - } - } - - - static void SubmitModificationJob(std::unique_ptr& modification, - bool isAnonymization, - RestApiPostCall& call, - const Json::Value& body, - ResourceType level) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::unique_ptr job(new ResourceModificationJob(context)); - - job->SetModification(modification.release(), level, isAnonymization); - job->SetOrigin(call); - SetKeepSource(*job, body); - - static const char* TRANSCODE = "Transcode"; - if (body.isMember(TRANSCODE)) - { - job->SetTranscode(SerializationToolbox::ReadString(body, TRANSCODE)); - } - - context.AddChildInstances(*job, call.GetUriComponent("id", "")); - job->AddTrailingStep(); - - OrthancRestApi::GetApi(call).SubmitCommandsJob - (call, job.release(), true /* synchronous by default */, body); - } - - - template - static void ModifyResource(RestApiPostCall& call) - { - std::unique_ptr modification(new DicomModification); - - Json::Value body; - ParseModifyRequest(body, *modification, call); - - modification->SetLevel(resourceType); - - SubmitModificationJob(modification, false /* not an anonymization */, - call, body, resourceType); - } - - - template - static void AnonymizeResource(RestApiPostCall& call) - { - std::unique_ptr modification(new DicomModification); - - Json::Value body; - ParseAnonymizationRequest(body, *modification, call); - - SubmitModificationJob(modification, true /* anonymization */, - call, body, resourceType); - } - - - static void StoreCreatedInstance(std::string& id /* out */, - RestApiPostCall& call, - ParsedDicomFile& dicom, - bool sendAnswer) - { - DicomInstanceToStore toStore; - toStore.SetOrigin(DicomInstanceOrigin::FromRest(call)); - toStore.SetParsedDicomFile(dicom); - - ServerContext& context = OrthancRestApi::GetContext(call); - StoreStatus status = context.Store(id, toStore, StoreInstanceMode_Default); - - if (status == StoreStatus_Failure) - { - throw OrthancException(ErrorCode_CannotStoreInstance); - } - - if (sendAnswer) - { - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status, id); - } - } - - - static void CreateDicomV1(ParsedDicomFile& dicom, - RestApiPostCall& call, - const Json::Value& request) - { - // curl http://localhost:8042/tools/create-dicom -X POST -d '{"PatientName":"Hello^World"}' - // curl http://localhost:8042/tools/create-dicom -X POST -d '{"PatientName":"Hello^World","PixelData":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gUGDDcB53FulQAAAElJREFUGNNtj0sSAEEEQ1+U+185s1CtmRkblQ9CZldsKHJDk6DLGLJa6chjh0ooQmpjXMM86zPwydGEj6Ed/UGykkEM8X+p3u8/8LcOJIWLGeMAAAAASUVORK5CYII="}' - - assert(request.isObject()); - LOG(WARNING) << "Using a deprecated call to /tools/create-dicom"; - - Json::Value::Members members = request.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - if (request[name].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_CreateDicomNotString); - } - - std::string value = request[name].asString(); - - DicomTag tag = FromDcmtkBridge::ParseTag(name); - if (tag == DICOM_TAG_PIXEL_DATA) - { - dicom.EmbedContent(value); - } - else - { - // This is V1, don't try and decode data URI scheme - dicom.ReplacePlainString(tag, value); - } - } - } - - - static void InjectTags(ParsedDicomFile& dicom, - const Json::Value& tags, - bool decodeBinaryTags, - const std::string& privateCreator) - { - if (tags.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadRequest, "Tags field is not an array"); - } - - // Inject the user-specified tags - Json::Value::Members members = tags.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const std::string& name = members[i]; - DicomTag tag = FromDcmtkBridge::ParseTag(name); - - if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - if (tag != DICOM_TAG_PATIENT_ID && - tag != DICOM_TAG_ACQUISITION_DATE && - tag != DICOM_TAG_ACQUISITION_TIME && - tag != DICOM_TAG_CONTENT_DATE && - tag != DICOM_TAG_CONTENT_TIME && - tag != DICOM_TAG_INSTANCE_CREATION_DATE && - tag != DICOM_TAG_INSTANCE_CREATION_TIME && - tag != DICOM_TAG_SERIES_DATE && - tag != DICOM_TAG_SERIES_TIME && - tag != DICOM_TAG_STUDY_DATE && - tag != DICOM_TAG_STUDY_TIME && - dicom.HasTag(tag)) - { - throw OrthancException(ErrorCode_CreateDicomOverrideTag, name); - } - - if (tag == DICOM_TAG_PIXEL_DATA) - { - throw OrthancException(ErrorCode_CreateDicomUseContent); - } - else - { - dicom.Replace(tag, tags[name], decodeBinaryTags, DicomReplaceMode_InsertIfAbsent, privateCreator); - } - } - } - } - - - static void CreateSeries(RestApiPostCall& call, - ParsedDicomFile& base /* in */, - const Json::Value& content, - bool decodeBinaryTags, - const std::string& privateCreator) - { - assert(content.isArray()); - assert(content.size() > 0); - ServerContext& context = OrthancRestApi::GetContext(call); - - base.ReplacePlainString(DICOM_TAG_IMAGES_IN_ACQUISITION, boost::lexical_cast(content.size())); - base.ReplacePlainString(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, "1"); - - std::string someInstance; - - try - { - for (Json::ArrayIndex i = 0; i < content.size(); i++) - { - std::unique_ptr dicom(base.Clone(false)); - const Json::Value* payload = NULL; - - if (content[i].type() == Json::stringValue) - { - payload = &content[i]; - } - else if (content[i].type() == Json::objectValue) - { - if (!content[i].isMember("Content")) - { - throw OrthancException(ErrorCode_CreateDicomNoPayload); - } - - payload = &content[i]["Content"]; - - if (content[i].isMember("Tags")) - { - InjectTags(*dicom, content[i]["Tags"], decodeBinaryTags, privateCreator); - } - } - - if (payload == NULL || - payload->type() != Json::stringValue) - { - throw OrthancException(ErrorCode_CreateDicomUseDataUriScheme); - } - - dicom->EmbedContent(payload->asString()); - dicom->ReplacePlainString(DICOM_TAG_INSTANCE_NUMBER, boost::lexical_cast(i + 1)); - dicom->ReplacePlainString(DICOM_TAG_IMAGE_INDEX, boost::lexical_cast(i + 1)); - - StoreCreatedInstance(someInstance, call, *dicom, false); - } - } - catch (OrthancException&) - { - // Error: Remove the newly-created series - - std::string series; - if (context.GetIndex().LookupParent(series, someInstance)) - { - Json::Value dummy; - context.GetIndex().DeleteResource(dummy, series, ResourceType_Series); - } - - throw; - } - - std::string series; - if (context.GetIndex().LookupParent(series, someInstance)) - { - OrthancRestApi::GetApi(call).AnswerStoredResource(call, series, ResourceType_Series, StoreStatus_Success); - } - } - - - static void CreateDicomV2(RestApiPostCall& call, - const Json::Value& request) - { - assert(request.isObject()); - ServerContext& context = OrthancRestApi::GetContext(call); - - if (!request.isMember("Tags") || - request["Tags"].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadRequest); - } - - ParsedDicomFile dicom(true); - - { - Encoding encoding; - - if (request["Tags"].isMember("SpecificCharacterSet")) - { - const char* tmp = request["Tags"]["SpecificCharacterSet"].asCString(); - if (!GetDicomEncoding(encoding, tmp)) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Unknown specific character set: " + std::string(tmp)); - } - } - else - { - encoding = GetDefaultDicomEncoding(); - } - - dicom.SetEncoding(encoding); - } - - ResourceType parentType = ResourceType_Instance; - - if (request.isMember("Parent")) - { - // Locate the parent tags - std::string parent = request["Parent"].asString(); - if (!context.GetIndex().LookupResourceType(parentType, parent)) - { - throw OrthancException(ErrorCode_CreateDicomBadParent); - } - - if (parentType == ResourceType_Instance) - { - throw OrthancException(ErrorCode_CreateDicomParentIsInstance); - } - - // Select one existing child instance of the parent resource, to - // retrieve all its tags - Json::Value siblingTags; - std::string siblingInstanceId; - - { - // Retrieve all the instances of the parent resource - std::list siblingInstances; - context.GetIndex().GetChildInstances(siblingInstances, parent); - - if (siblingInstances.empty()) - { - // Error: No instance (should never happen) - throw OrthancException(ErrorCode_InternalError); - } - - siblingInstanceId = siblingInstances.front(); - context.ReadDicomAsJson(siblingTags, siblingInstanceId); - } - - - // Choose the same encoding as the parent resource - { - static const char* SPECIFIC_CHARACTER_SET = "0008,0005"; - - if (siblingTags.isMember(SPECIFIC_CHARACTER_SET)) - { - Encoding encoding; - - if (!siblingTags[SPECIFIC_CHARACTER_SET].isMember("Value") || - siblingTags[SPECIFIC_CHARACTER_SET]["Value"].type() != Json::stringValue || - !GetDicomEncoding(encoding, siblingTags[SPECIFIC_CHARACTER_SET]["Value"].asCString())) - { - LOG(WARNING) << "Instance with an incorrect Specific Character Set, " - << "using the default Orthanc encoding: " << siblingInstanceId; - encoding = GetDefaultDicomEncoding(); - } - - dicom.SetEncoding(encoding); - } - } - - - // Retrieve the tags for all the parent modules - typedef std::set ModuleTags; - ModuleTags moduleTags; - - ResourceType type = parentType; - for (;;) - { - DicomTag::AddTagsForModule(moduleTags, GetModule(type)); - - if (type == ResourceType_Patient) - { - break; // We're done - } - - // Go up - std::string tmp; - if (!context.GetIndex().LookupParent(tmp, parent)) - { - throw OrthancException(ErrorCode_InternalError); - } - - parent = tmp; - type = GetParentResourceType(type); - } - - for (ModuleTags::const_iterator it = moduleTags.begin(); - it != moduleTags.end(); ++it) - { - std::string t = it->Format(); - if (siblingTags.isMember(t)) - { - const Json::Value& tag = siblingTags[t]; - if (tag["Type"] == "Null") - { - dicom.ReplacePlainString(*it, ""); - } - else if (tag["Type"] == "String") - { - std::string value = tag["Value"].asString(); // This is an UTF-8 value (as it comes from JSON) - dicom.ReplacePlainString(*it, value); - } - } - } - } - - - bool decodeBinaryTags = true; - if (request.isMember("InterpretBinaryTags")) - { - const Json::Value& v = request["InterpretBinaryTags"]; - if (v.type() != Json::booleanValue) - { - throw OrthancException(ErrorCode_BadRequest); - } - - decodeBinaryTags = v.asBool(); - } - - - // New argument in Orthanc 1.6.0 - std::string privateCreator; - if (request.isMember("PrivateCreator")) - { - const Json::Value& v = request["PrivateCreator"]; - if (v.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest); - } - - privateCreator = v.asString(); - } - else - { - OrthancConfiguration::ReaderLock lock; - privateCreator = lock.GetConfiguration().GetDefaultPrivateCreator(); - } - - - // Inject time-related information - std::string date, time; - SystemToolbox::GetNowDicom(date, time, true /* use UTC time (not local time) */); - dicom.ReplacePlainString(DICOM_TAG_ACQUISITION_DATE, date); - dicom.ReplacePlainString(DICOM_TAG_ACQUISITION_TIME, time); - dicom.ReplacePlainString(DICOM_TAG_CONTENT_DATE, date); - dicom.ReplacePlainString(DICOM_TAG_CONTENT_TIME, time); - dicom.ReplacePlainString(DICOM_TAG_INSTANCE_CREATION_DATE, date); - dicom.ReplacePlainString(DICOM_TAG_INSTANCE_CREATION_TIME, time); - - if (parentType == ResourceType_Patient || - parentType == ResourceType_Study || - parentType == ResourceType_Instance /* no parent */) - { - dicom.ReplacePlainString(DICOM_TAG_SERIES_DATE, date); - dicom.ReplacePlainString(DICOM_TAG_SERIES_TIME, time); - } - - if (parentType == ResourceType_Patient || - parentType == ResourceType_Instance /* no parent */) - { - dicom.ReplacePlainString(DICOM_TAG_STUDY_DATE, date); - dicom.ReplacePlainString(DICOM_TAG_STUDY_TIME, time); - } - - - InjectTags(dicom, request["Tags"], decodeBinaryTags, privateCreator); - - - // Inject the content (either an image, or a PDF file) - if (request.isMember("Content")) - { - const Json::Value& content = request["Content"]; - - if (content.type() == Json::stringValue) - { - dicom.EmbedContent(request["Content"].asString()); - - } - else if (content.type() == Json::arrayValue) - { - if (content.size() > 0) - { - // Let's create a series instead of a single instance - CreateSeries(call, dicom, content, decodeBinaryTags, privateCreator); - return; - } - } - else - { - throw OrthancException(ErrorCode_CreateDicomUseDataUriScheme); - } - } - - std::string id; - StoreCreatedInstance(id, call, dicom, true); - } - - - static void CreateDicom(RestApiPostCall& call) - { - Json::Value request; - if (!call.ParseJsonRequest(request) || - !request.isObject()) - { - throw OrthancException(ErrorCode_BadRequest); - } - - if (request.isMember("Tags")) - { - CreateDicomV2(call, request); - } - else - { - // Compatibility with Orthanc <= 0.9.3 - ParsedDicomFile dicom(true); - CreateDicomV1(dicom, call, request); - - std::string id; - StoreCreatedInstance(id, call, dicom, true); - } - } - - - static void SplitStudy(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value request; - if (!call.ParseJsonRequest(request)) - { - // Bad JSON request - throw OrthancException(ErrorCode_BadFileFormat); - } - - const std::string study = call.GetUriComponent("id", ""); - - std::unique_ptr job(new SplitStudyJob(context, study)); - job->SetOrigin(call); - - std::vector series; - SerializationToolbox::ReadArrayOfStrings(series, request, "Series"); - - for (size_t i = 0; i < series.size(); i++) - { - job->AddSourceSeries(series[i]); - } - - job->AddTrailingStep(); - - SetKeepSource(*job, request); - - static const char* REMOVE = "Remove"; - if (request.isMember(REMOVE)) - { - if (request[REMOVE].type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - for (Json::Value::ArrayIndex i = 0; i < request[REMOVE].size(); i++) - { - if (request[REMOVE][i].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - job->Remove(FromDcmtkBridge::ParseTag(request[REMOVE][i].asCString())); - } - } - } - - static const char* REPLACE = "Replace"; - if (request.isMember(REPLACE)) - { - if (request[REPLACE].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - Json::Value::Members tags = request[REPLACE].getMemberNames(); - - for (size_t i = 0; i < tags.size(); i++) - { - const Json::Value& value = request[REPLACE][tags[i]]; - - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - else - { - job->Replace(FromDcmtkBridge::ParseTag(tags[i]), value.asString()); - } - } - } - - OrthancRestApi::GetApi(call).SubmitCommandsJob - (call, job.release(), true /* synchronous by default */, request); - } - - - static void MergeStudy(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value request; - if (!call.ParseJsonRequest(request)) - { - // Bad JSON request - throw OrthancException(ErrorCode_BadFileFormat); - } - - const std::string study = call.GetUriComponent("id", ""); - - std::unique_ptr job(new MergeStudyJob(context, study)); - job->SetOrigin(call); - - std::vector resources; - SerializationToolbox::ReadArrayOfStrings(resources, request, "Resources"); - - for (size_t i = 0; i < resources.size(); i++) - { - job->AddSource(resources[i]); - } - - job->AddTrailingStep(); - - SetKeepSource(*job, request); - - OrthancRestApi::GetApi(call).SubmitCommandsJob - (call, job.release(), true /* synchronous by default */, request); - } - - - void OrthancRestApi::RegisterAnonymizeModify() - { - Register("/instances/{id}/modify", ModifyInstance); - Register("/series/{id}/modify", ModifyResource); - Register("/studies/{id}/modify", ModifyResource); - Register("/patients/{id}/modify", ModifyResource); - - Register("/instances/{id}/anonymize", AnonymizeInstance); - Register("/series/{id}/anonymize", AnonymizeResource); - Register("/studies/{id}/anonymize", AnonymizeResource); - Register("/patients/{id}/anonymize", AnonymizeResource); - - Register("/tools/create-dicom", CreateDicom); - - Register("/studies/{id}/split", SplitStudy); - Register("/studies/{id}/merge", MergeStudy); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,333 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../../Core/Compression/GzipCompressor.h" -#include "../../Core/Logging.h" -#include "../../Core/MetricsRegistry.h" -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - -#include - -namespace Orthanc -{ - static void SetupResourceAnswer(Json::Value& result, - const std::string& publicId, - ResourceType resourceType, - StoreStatus status) - { - result = Json::objectValue; - - if (status != StoreStatus_Failure) - { - result["ID"] = publicId; - result["Path"] = GetBasePath(resourceType, publicId); - } - - result["Status"] = EnumerationToString(status); - } - - - void OrthancRestApi::AnswerStoredInstance(RestApiPostCall& call, - DicomInstanceToStore& instance, - StoreStatus status, - const std::string& instanceId) const - { - Json::Value result; - SetupResourceAnswer(result, instanceId, ResourceType_Instance, status); - - result["ParentPatient"] = instance.GetHasher().HashPatient(); - result["ParentStudy"] = instance.GetHasher().HashStudy(); - result["ParentSeries"] = instance.GetHasher().HashSeries(); - - call.GetOutput().AnswerJson(result); - } - - - void OrthancRestApi::AnswerStoredResource(RestApiPostCall& call, - const std::string& publicId, - ResourceType resourceType, - StoreStatus status) const - { - Json::Value result; - SetupResourceAnswer(result, publicId, resourceType, status); - call.GetOutput().AnswerJson(result); - } - - - void OrthancRestApi::ResetOrthanc(RestApiPostCall& call) - { - OrthancRestApi::GetApi(call).leaveBarrier_ = true; - OrthancRestApi::GetApi(call).resetRequestReceived_ = true; - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - - - void OrthancRestApi::ShutdownOrthanc(RestApiPostCall& call) - { - OrthancRestApi::GetApi(call).leaveBarrier_ = true; - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - LOG(WARNING) << "Shutdown request received"; - } - - - - - - // Upload of DICOM files through HTTP --------------------------------------- - - static void UploadDicomFile(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - LOG(INFO) << "Receiving a DICOM file of " << call.GetBodySize() << " bytes through HTTP"; - - if (call.GetBodySize() == 0) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Received an empty DICOM file"); - } - - // The lifetime of "dicom" must be longer than "toStore", as the - // latter can possibly store a reference to the former (*) - std::string dicom; - - DicomInstanceToStore toStore; - toStore.SetOrigin(DicomInstanceOrigin::FromRest(call)); - - if (boost::iequals(call.GetHttpHeader("content-encoding", ""), "gzip")) - { - GzipCompressor compressor; - compressor.Uncompress(dicom, call.GetBodyData(), call.GetBodySize()); - toStore.SetBuffer(dicom.c_str(), dicom.size()); // (*) - } - else - { - toStore.SetBuffer(call.GetBodyData(), call.GetBodySize()); - } - - std::string publicId; - StoreStatus status = context.Store(publicId, toStore, StoreInstanceMode_Default); - - OrthancRestApi::GetApi(call).AnswerStoredInstance(call, toStore, status, publicId); - } - - - - // Registration of the various REST handlers -------------------------------- - - OrthancRestApi::OrthancRestApi(ServerContext& context) : - context_(context), - leaveBarrier_(false), - resetRequestReceived_(false), - activeRequests_(context.GetMetricsRegistry(), - "orthanc_rest_api_active_requests", - MetricsType_MaxOver10Seconds) - { - RegisterSystem(); - - RegisterChanges(); - RegisterResources(); - RegisterModalities(); - RegisterAnonymizeModify(); - RegisterArchive(); - - Register("/instances", UploadDicomFile); - - // Auto-generated directories - Register("/tools", RestApi::AutoListChildren); - Register("/tools/reset", ResetOrthanc); - Register("/tools/shutdown", ShutdownOrthanc); - Register("/instances/{id}/frames/{frame}", RestApi::AutoListChildren); - } - - - bool OrthancRestApi::Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize) - { - MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_rest_api_duration_ms"); - MetricsRegistry::ActiveCounter counter(activeRequests_); - - return RestApi::Handle(output, origin, remoteIp, username, method, - uri, headers, getArguments, bodyData, bodySize); - } - - - ServerContext& OrthancRestApi::GetContext(RestApiCall& call) - { - return GetApi(call).context_; - } - - - ServerIndex& OrthancRestApi::GetIndex(RestApiCall& call) - { - return GetContext(call).GetIndex(); - } - - - - static const char* KEY_PERMISSIVE = "Permissive"; - static const char* KEY_PRIORITY = "Priority"; - static const char* KEY_SYNCHRONOUS = "Synchronous"; - static const char* KEY_ASYNCHRONOUS = "Asynchronous"; - - - bool OrthancRestApi::IsSynchronousJobRequest(bool isDefaultSynchronous, - const Json::Value& body) - { - if (body.type() != Json::objectValue) - { - return isDefaultSynchronous; - } - else if (body.isMember(KEY_SYNCHRONOUS)) - { - return SerializationToolbox::ReadBoolean(body, KEY_SYNCHRONOUS); - } - else if (body.isMember(KEY_ASYNCHRONOUS)) - { - return !SerializationToolbox::ReadBoolean(body, KEY_ASYNCHRONOUS); - } - else - { - return isDefaultSynchronous; - } - } - - - unsigned int OrthancRestApi::GetJobRequestPriority(const Json::Value& body) - { - if (body.type() != Json::objectValue || - !body.isMember(KEY_PRIORITY)) - { - return 0; // Default priority - } - else - { - return SerializationToolbox::ReadInteger(body, KEY_PRIORITY); - } - } - - - void OrthancRestApi::SubmitGenericJob(RestApiOutput& output, - ServerContext& context, - IJob* job, - bool synchronous, - int priority) - { - std::unique_ptr raii(job); - - if (job == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - if (synchronous) - { - Json::Value successContent; - context.GetJobsEngine().GetRegistry().SubmitAndWait - (successContent, raii.release(), priority); - - // Success in synchronous execution - output.AnswerJson(successContent); - } - else - { - // Asynchronous mode: Submit the job, but don't wait for its completion - std::string id; - context.GetJobsEngine().GetRegistry().Submit - (id, raii.release(), priority); - - Json::Value v; - v["ID"] = id; - v["Path"] = "/jobs/" + id; - output.AnswerJson(v); - } - } - - - void OrthancRestApi::SubmitGenericJob(RestApiPostCall& call, - IJob* job, - bool isDefaultSynchronous, - const Json::Value& body) const - { - std::unique_ptr raii(job); - - if (body.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - bool synchronous = IsSynchronousJobRequest(isDefaultSynchronous, body); - int priority = GetJobRequestPriority(body); - - SubmitGenericJob(call.GetOutput(), context_, raii.release(), synchronous, priority); - } - - - void OrthancRestApi::SubmitCommandsJob(RestApiPostCall& call, - SetOfCommandsJob* job, - bool isDefaultSynchronous, - const Json::Value& body) const - { - std::unique_ptr raii(job); - - if (body.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - job->SetDescription("REST API"); - - if (body.isMember(KEY_PERMISSIVE)) - { - job->SetPermissive(SerializationToolbox::ReadBoolean(body, KEY_PERMISSIVE)); - } - else - { - job->SetPermissive(false); - } - - SubmitGenericJob(call, raii.release(), isDefaultSynchronous, body); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestApi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,143 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomParsing/DicomModification.h" -#include "../../Core/JobsEngine/SetOfCommandsJob.h" -#include "../../Core/MetricsRegistry.h" -#include "../../Core/RestApi/RestApi.h" -#include "../ServerEnumerations.h" - -#include - -namespace Orthanc -{ - class ServerContext; - class ServerIndex; - class DicomInstanceToStore; - - class OrthancRestApi : public RestApi - { - public: - typedef std::set SetOfStrings; - - private: - ServerContext& context_; - bool leaveBarrier_; - bool resetRequestReceived_; - MetricsRegistry::SharedMetrics activeRequests_; - - void RegisterSystem(); - - void RegisterChanges(); - - void RegisterResources(); - - void RegisterModalities(); - - void RegisterAnonymizeModify(); - - void RegisterArchive(); - - static void ResetOrthanc(RestApiPostCall& call); - - static void ShutdownOrthanc(RestApiPostCall& call); - - public: - OrthancRestApi(ServerContext& context); - - virtual bool Handle(HttpOutput& output, - RequestOrigin origin, - const char* remoteIp, - const char* username, - HttpMethod method, - const UriComponents& uri, - const Arguments& headers, - const GetArguments& getArguments, - const void* bodyData, - size_t bodySize) ORTHANC_OVERRIDE; - - const bool& LeaveBarrierFlag() const - { - return leaveBarrier_; - } - - bool IsResetRequestReceived() const - { - return resetRequestReceived_; - } - - static OrthancRestApi& GetApi(RestApiCall& call) - { - return dynamic_cast(call.GetContext()); - } - - static ServerContext& GetContext(RestApiCall& call); - - static ServerIndex& GetIndex(RestApiCall& call); - - // WARNING: "instanceId" can be different from - // "instance.GetHasher().HashInstance()" if transcoding is enabled - void AnswerStoredInstance(RestApiPostCall& call, - DicomInstanceToStore& instance, - StoreStatus status, - const std::string& instanceId) const; - - void AnswerStoredResource(RestApiPostCall& call, - const std::string& publicId, - ResourceType resourceType, - StoreStatus status) const; - - static bool IsSynchronousJobRequest(bool isDefaultSynchronous, - const Json::Value& body); - - static unsigned int GetJobRequestPriority(const Json::Value& body); - - static void SubmitGenericJob(RestApiOutput& output, - ServerContext& context, - IJob* job, - bool synchronous, - int priority); - - void SubmitGenericJob(RestApiPostCall& call, - IJob* job, - bool isDefaultSynchronous, - const Json::Value& body) const; - - void SubmitCommandsJob(RestApiPostCall& call, - SetOfCommandsJob* job, - bool isDefaultSynchronous, - const Json::Value& body) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../../Core/HttpServer/FilesystemHttpSender.h" -#include "../../Core/OrthancException.h" -#include "../../Core/SerializationToolbox.h" -#include "../OrthancConfiguration.h" -#include "../ServerContext.h" -#include "../ServerJobs/ArchiveJob.h" - - -namespace Orthanc -{ - static const char* const KEY_RESOURCES = "Resources"; - static const char* const KEY_EXTENDED = "Extended"; - static const char* const KEY_TRANSCODE = "Transcode"; - - static void AddResourcesOfInterestFromArray(ArchiveJob& job, - const Json::Value& resources) - { - if (resources.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Expected a list of strings (Orthanc identifiers)"); - } - - for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) - { - if (resources[i].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Expected a list of strings (Orthanc identifiers)"); - } - else - { - job.AddResource(resources[i].asString()); - } - } - } - - - static void AddResourcesOfInterest(ArchiveJob& job /* inout */, - const Json::Value& body /* in */) - { - if (body.type() == Json::arrayValue) - { - AddResourcesOfInterestFromArray(job, body); - } - else if (body.type() == Json::objectValue) - { - if (body.isMember(KEY_RESOURCES)) - { - AddResourcesOfInterestFromArray(job, body[KEY_RESOURCES]); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing field " + std::string(KEY_RESOURCES) + - " in the JSON body"); - } - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - static DicomTransferSyntax GetTransferSyntax(const std::string& value) - { - DicomTransferSyntax syntax; - if (LookupTransferSyntax(syntax, value)) - { - return syntax; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Unknown transfer syntax: " + value); - } - } - - - static void GetJobParameters(bool& synchronous, /* out */ - bool& extended, /* out */ - bool& transcode, /* out */ - DicomTransferSyntax& syntax, /* out */ - int& priority, /* out */ - const Json::Value& body, /* in */ - const bool defaultExtended /* in */) - { - synchronous = OrthancRestApi::IsSynchronousJobRequest - (true /* synchronous by default */, body); - - priority = OrthancRestApi::GetJobRequestPriority(body); - - if (body.type() == Json::objectValue && - body.isMember(KEY_EXTENDED)) - { - extended = SerializationToolbox::ReadBoolean(body, KEY_EXTENDED); - } - else - { - extended = defaultExtended; - } - - if (body.type() == Json::objectValue && - body.isMember(KEY_TRANSCODE)) - { - transcode = true; - syntax = GetTransferSyntax(SerializationToolbox::ReadString(body, KEY_TRANSCODE)); - } - else - { - transcode = false; - } - } - - - static void SubmitJob(RestApiOutput& output, - ServerContext& context, - std::unique_ptr& job, - int priority, - bool synchronous, - const std::string& filename) - { - if (job.get() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - job->SetDescription("REST API"); - - if (synchronous) - { - boost::shared_ptr tmp; - - { - OrthancConfiguration::ReaderLock lock; - tmp.reset(lock.GetConfiguration().CreateTemporaryFile()); - } - - job->SetSynchronousTarget(tmp); - - Json::Value publicContent; - context.GetJobsEngine().GetRegistry().SubmitAndWait - (publicContent, job.release(), priority); - - { - // The archive is now created: Prepare the sending of the ZIP file - FilesystemHttpSender sender(tmp->GetPath(), MimeType_Zip); - sender.SetContentFilename(filename); - - // Send the ZIP - output.AnswerStream(sender); - } - } - else - { - OrthancRestApi::SubmitGenericJob(output, context, job.release(), false, priority); - } - } - - - template - static void CreateBatch(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value body; - if (call.ParseJsonRequest(body)) - { - bool synchronous, extended, transcode; - DicomTransferSyntax transferSyntax; - int priority; - GetJobParameters(synchronous, extended, transcode, transferSyntax, - priority, body, DEFAULT_IS_EXTENDED); - - std::unique_ptr job(new ArchiveJob(context, IS_MEDIA, extended)); - AddResourcesOfInterest(*job, body); - - if (transcode) - { - job->SetTranscode(transferSyntax); - } - - SubmitJob(call.GetOutput(), context, job, priority, synchronous, "Archive.zip"); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Expected a list of resources to archive in the body"); - } - } - - - template - static void CreateSingleGet(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string id = call.GetUriComponent("id", ""); - - bool extended; - if (IS_MEDIA) - { - extended = call.HasArgument("extended"); - } - else - { - extended = false; - } - - std::unique_ptr job(new ArchiveJob(context, IS_MEDIA, extended)); - job->AddResource(id); - - static const char* const TRANSCODE = "transcode"; - if (call.HasArgument(TRANSCODE)) - { - job->SetTranscode(GetTransferSyntax(call.GetArgument(TRANSCODE, ""))); - } - - SubmitJob(call.GetOutput(), context, job, 0 /* priority */, - true /* synchronous */, id + ".zip"); - } - - - template - static void CreateSinglePost(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string id = call.GetUriComponent("id", ""); - - Json::Value body; - if (call.ParseJsonRequest(body)) - { - bool synchronous, extended, transcode; - DicomTransferSyntax transferSyntax; - int priority; - GetJobParameters(synchronous, extended, transcode, transferSyntax, - priority, body, DEFAULT_IS_EXTENDED); - - std::unique_ptr job(new ArchiveJob(context, IS_MEDIA, extended)); - job->AddResource(id); - - if (transcode) - { - job->SetTranscode(transferSyntax); - } - - SubmitJob(call.GetOutput(), context, job, priority, synchronous, id + ".zip"); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - void OrthancRestApi::RegisterArchive() - { - Register("/patients/{id}/archive", - CreateSingleGet); - Register("/studies/{id}/archive", - CreateSingleGet); - Register("/series/{id}/archive", - CreateSingleGet); - - Register("/patients/{id}/archive", - CreateSinglePost); - Register("/studies/{id}/archive", - CreateSinglePost); - Register("/series/{id}/archive", - CreateSinglePost); - - Register("/patients/{id}/media", - CreateSingleGet); - Register("/studies/{id}/media", - CreateSingleGet); - Register("/series/{id}/media", - CreateSingleGet); - - Register("/patients/{id}/media", - CreateSinglePost); - Register("/studies/{id}/media", - CreateSinglePost); - Register("/series/{id}/media", - CreateSinglePost); - - Register("/tools/create-archive", - CreateBatch); - Register("/tools/create-media", - CreateBatch); - Register("/tools/create-media-extended", - CreateBatch); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestChanges.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestChanges.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestChanges.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestChanges.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../ServerContext.h" - -namespace Orthanc -{ - // Changes API -------------------------------------------------------------- - - static void GetSinceAndLimit(int64_t& since, - unsigned int& limit, - bool& last, - const RestApiGetCall& call) - { - static const unsigned int DEFAULT_LIMIT = 100; - - if (call.HasArgument("last")) - { - last = true; - return; - } - - last = false; - - try - { - since = boost::lexical_cast(call.GetArgument("since", "0")); - limit = boost::lexical_cast(call.GetArgument("limit", boost::lexical_cast(DEFAULT_LIMIT))); - } - catch (boost::bad_lexical_cast&) - { - since = 0; - limit = DEFAULT_LIMIT; - return; - } - } - - static void GetChanges(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - //std::string filter = GetArgument(getArguments, "filter", ""); - int64_t since; - unsigned int limit; - bool last; - GetSinceAndLimit(since, limit, last, call); - - Json::Value result; - if (last) - { - context.GetIndex().GetLastChange(result); - } - else - { - context.GetIndex().GetChanges(result, since, limit); - } - - call.GetOutput().AnswerJson(result); - } - - - static void DeleteChanges(RestApiDeleteCall& call) - { - OrthancRestApi::GetIndex(call).DeleteChanges(); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - // Exports API -------------------------------------------------------------- - - static void GetExports(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - int64_t since; - unsigned int limit; - bool last; - GetSinceAndLimit(since, limit, last, call); - - Json::Value result; - if (last) - { - context.GetIndex().GetLastExportedResource(result); - } - else - { - context.GetIndex().GetExportedResources(result, since, limit); - } - - call.GetOutput().AnswerJson(result); - } - - - static void DeleteExports(RestApiDeleteCall& call) - { - OrthancRestApi::GetIndex(call).DeleteExportedResources(); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - void OrthancRestApi::RegisterChanges() - { - Register("/changes", GetChanges); - Register("/changes", DeleteChanges); - Register("/exports", GetExports); - Register("/exports", DeleteExports); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1647 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../../Core/Cache/SharedArchive.h" -#include "../../Core/DicomNetworking/DicomAssociation.h" -#include "../../Core/DicomNetworking/DicomControlUserConnection.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" - -#include "../OrthancConfiguration.h" -#include "../QueryRetrieveHandler.h" -#include "../ServerContext.h" -#include "../ServerJobs/DicomModalityStoreJob.h" -#include "../ServerJobs/DicomMoveScuJob.h" -#include "../ServerJobs/OrthancPeerStoreJob.h" -#include "../ServerToolbox.h" -#include "../StorageCommitmentReports.h" - - -namespace Orthanc -{ - static const char* const KEY_LEVEL = "Level"; - static const char* const KEY_LOCAL_AET = "LocalAet"; - static const char* const KEY_NORMALIZE = "Normalize"; - static const char* const KEY_QUERY = "Query"; - static const char* const KEY_RESOURCES = "Resources"; - static const char* const KEY_TARGET_AET = "TargetAet"; - static const char* const KEY_TIMEOUT = "Timeout"; - static const char* const SOP_CLASS_UID = "SOPClassUID"; - static const char* const SOP_INSTANCE_UID = "SOPInstanceUID"; - - static RemoteModalityParameters MyGetModalityUsingSymbolicName(const std::string& name) - { - OrthancConfiguration::ReaderLock lock; - return lock.GetConfiguration().GetModalityUsingSymbolicName(name); - } - - - static void InjectAssociationTimeout(DicomAssociationParameters& params, - const Json::Value& body) - { - if (body.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON object"); - } - else if (body.isMember(KEY_TIMEOUT)) - { - // New in Orthanc 1.7.0 - params.SetTimeout(SerializationToolbox::ReadUnsignedInteger(body, KEY_TIMEOUT)); - } - } - - static DicomAssociationParameters GetAssociationParameters(RestApiPostCall& call, - const Json::Value& body) - { - const std::string& localAet = - OrthancRestApi::GetContext(call).GetDefaultLocalApplicationEntityTitle(); - const RemoteModalityParameters remote = - MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); - - DicomAssociationParameters params(localAet, remote); - InjectAssociationTimeout(params, body); - - return params; - } - - - static DicomAssociationParameters GetAssociationParameters(RestApiPostCall& call) - { - Json::Value body; - call.ParseJsonRequest(body); - return GetAssociationParameters(call, body); - } - - - /*************************************************************************** - * DICOM C-Echo SCU - ***************************************************************************/ - - static void DicomEcho(RestApiPostCall& call) - { - DicomControlUserConnection connection(GetAssociationParameters(call)); - - if (connection.Echo()) - { - // Echo has succeeded - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - return; - } - else - { - // Echo has failed - call.GetOutput().SignalError(HttpStatus_500_InternalServerError); - } - } - - - - /*************************************************************************** - * DICOM C-Find SCU => DEPRECATED! - ***************************************************************************/ - - static bool MergeQueryAndTemplate(DicomMap& result, - const RestApiCall& call) - { - Json::Value query; - - if (!call.ParseJsonRequest(query) || - query.type() != Json::objectValue) - { - return false; - } - - Json::Value::Members members = query.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - DicomTag t = FromDcmtkBridge::ParseTag(members[i]); - result.SetValue(t, query[members[i]].asString(), false); - } - - return true; - } - - - static void FindPatient(DicomFindAnswers& result, - DicomControlUserConnection& connection, - const DicomMap& fields) - { - // Only keep the filters from "fields" that are related to the patient - DicomMap s; - fields.ExtractPatientInformation(s); - connection.Find(result, ResourceType_Patient, s, true /* normalize */); - } - - - static void FindStudy(DicomFindAnswers& result, - DicomControlUserConnection& connection, - const DicomMap& fields) - { - // Only keep the filters from "fields" that are related to the study - DicomMap s; - fields.ExtractStudyInformation(s); - - s.CopyTagIfExists(fields, DICOM_TAG_PATIENT_ID); - s.CopyTagIfExists(fields, DICOM_TAG_ACCESSION_NUMBER); - s.CopyTagIfExists(fields, DICOM_TAG_MODALITIES_IN_STUDY); - - connection.Find(result, ResourceType_Study, s, true /* normalize */); - } - - static void FindSeries(DicomFindAnswers& result, - DicomControlUserConnection& connection, - const DicomMap& fields) - { - // Only keep the filters from "fields" that are related to the series - DicomMap s; - fields.ExtractSeriesInformation(s); - - s.CopyTagIfExists(fields, DICOM_TAG_PATIENT_ID); - s.CopyTagIfExists(fields, DICOM_TAG_ACCESSION_NUMBER); - s.CopyTagIfExists(fields, DICOM_TAG_STUDY_INSTANCE_UID); - - connection.Find(result, ResourceType_Series, s, true /* normalize */); - } - - static void FindInstance(DicomFindAnswers& result, - DicomControlUserConnection& connection, - const DicomMap& fields) - { - // Only keep the filters from "fields" that are related to the instance - DicomMap s; - fields.ExtractInstanceInformation(s); - - s.CopyTagIfExists(fields, DICOM_TAG_PATIENT_ID); - s.CopyTagIfExists(fields, DICOM_TAG_ACCESSION_NUMBER); - s.CopyTagIfExists(fields, DICOM_TAG_STUDY_INSTANCE_UID); - s.CopyTagIfExists(fields, DICOM_TAG_SERIES_INSTANCE_UID); - - connection.Find(result, ResourceType_Instance, s, true /* normalize */); - } - - - static void DicomFindPatient(RestApiPostCall& call) - { - LOG(WARNING) << "This URI is deprecated: " << call.FlattenUri(); - - DicomMap fields; - DicomMap::SetupFindPatientTemplate(fields); - if (!MergeQueryAndTemplate(fields, call)) - { - return; - } - - DicomFindAnswers answers(false); - - { - DicomControlUserConnection connection(GetAssociationParameters(call)); - FindPatient(answers, connection, fields); - } - - Json::Value result; - answers.ToJson(result, true); - call.GetOutput().AnswerJson(result); - } - - static void DicomFindStudy(RestApiPostCall& call) - { - LOG(WARNING) << "This URI is deprecated: " << call.FlattenUri(); - - DicomMap fields; - DicomMap::SetupFindStudyTemplate(fields); - if (!MergeQueryAndTemplate(fields, call)) - { - return; - } - - if (fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).GetContent().size() <= 2 && - fields.GetValue(DICOM_TAG_PATIENT_ID).GetContent().size() <= 2) - { - return; - } - - DicomFindAnswers answers(false); - - { - DicomControlUserConnection connection(GetAssociationParameters(call)); - FindStudy(answers, connection, fields); - } - - Json::Value result; - answers.ToJson(result, true); - call.GetOutput().AnswerJson(result); - } - - static void DicomFindSeries(RestApiPostCall& call) - { - LOG(WARNING) << "This URI is deprecated: " << call.FlattenUri(); - - DicomMap fields; - DicomMap::SetupFindSeriesTemplate(fields); - if (!MergeQueryAndTemplate(fields, call)) - { - return; - } - - if ((fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).GetContent().size() <= 2 && - fields.GetValue(DICOM_TAG_PATIENT_ID).GetContent().size() <= 2) || - fields.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent().size() <= 2) - { - return; - } - - DicomFindAnswers answers(false); - - { - DicomControlUserConnection connection(GetAssociationParameters(call)); - FindSeries(answers, connection, fields); - } - - Json::Value result; - answers.ToJson(result, true); - call.GetOutput().AnswerJson(result); - } - - static void DicomFindInstance(RestApiPostCall& call) - { - LOG(WARNING) << "This URI is deprecated: " << call.FlattenUri(); - - DicomMap fields; - DicomMap::SetupFindInstanceTemplate(fields); - if (!MergeQueryAndTemplate(fields, call)) - { - return; - } - - if ((fields.GetValue(DICOM_TAG_ACCESSION_NUMBER).GetContent().size() <= 2 && - fields.GetValue(DICOM_TAG_PATIENT_ID).GetContent().size() <= 2) || - fields.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent().size() <= 2 || - fields.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent().size() <= 2) - { - return; - } - - DicomFindAnswers answers(false); - - { - DicomControlUserConnection connection(GetAssociationParameters(call)); - FindInstance(answers, connection, fields); - } - - Json::Value result; - answers.ToJson(result, true); - call.GetOutput().AnswerJson(result); - } - - - static void CopyTagIfExists(DicomMap& target, - ParsedDicomFile& source, - const DicomTag& tag) - { - std::string tmp; - if (source.GetTagValue(tmp, tag)) - { - target.SetValue(tag, tmp, false); - } - } - - - static void DicomFind(RestApiPostCall& call) - { - LOG(WARNING) << "This URI is deprecated: " << call.FlattenUri(); - - DicomMap m; - DicomMap::SetupFindPatientTemplate(m); - if (!MergeQueryAndTemplate(m, call)) - { - return; - } - - DicomControlUserConnection connection(GetAssociationParameters(call)); - - DicomFindAnswers patients(false); - FindPatient(patients, connection, m); - - // Loop over the found patients - Json::Value result = Json::arrayValue; - for (size_t i = 0; i < patients.GetSize(); i++) - { - Json::Value patient; - patients.ToJson(patient, i, true); - - DicomMap::SetupFindStudyTemplate(m); - if (!MergeQueryAndTemplate(m, call)) - { - return; - } - - CopyTagIfExists(m, patients.GetAnswer(i), DICOM_TAG_PATIENT_ID); - - DicomFindAnswers studies(false); - FindStudy(studies, connection, m); - - patient["Studies"] = Json::arrayValue; - - // Loop over the found studies - for (size_t j = 0; j < studies.GetSize(); j++) - { - Json::Value study; - studies.ToJson(study, j, true); - - DicomMap::SetupFindSeriesTemplate(m); - if (!MergeQueryAndTemplate(m, call)) - { - return; - } - - CopyTagIfExists(m, studies.GetAnswer(j), DICOM_TAG_PATIENT_ID); - CopyTagIfExists(m, studies.GetAnswer(j), DICOM_TAG_STUDY_INSTANCE_UID); - - DicomFindAnswers series(false); - FindSeries(series, connection, m); - - // Loop over the found series - study["Series"] = Json::arrayValue; - for (size_t k = 0; k < series.GetSize(); k++) - { - Json::Value series2; - series.ToJson(series2, k, true); - study["Series"].append(series2); - } - - patient["Studies"].append(study); - } - - result.append(patient); - } - - call.GetOutput().AnswerJson(result); - } - - - - /*************************************************************************** - * DICOM C-Find and C-Move SCU => Recommended since Orthanc 0.9.0 - ***************************************************************************/ - - static void AnswerQueryHandler(RestApiPostCall& call, - std::unique_ptr& handler) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - if (handler.get() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - handler->Run(); - - std::string s = context.GetQueryRetrieveArchive().Add(handler.release()); - Json::Value result = Json::objectValue; - result["ID"] = s; - result["Path"] = "/queries/" + s; - - call.GetOutput().AnswerJson(result); - } - - - static void DicomQuery(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - Json::Value request; - - if (!call.ParseJsonRequest(request) || - request.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON object"); - } - else if (!request.isMember(KEY_LEVEL) || - request[KEY_LEVEL].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The JSON body must contain field " + std::string(KEY_LEVEL)); - } - else if (request.isMember(KEY_NORMALIZE) && - request[KEY_NORMALIZE].type() != Json::booleanValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The field " + std::string(KEY_NORMALIZE) + " must contain a Boolean"); - } - else if (request.isMember(KEY_QUERY) && - request[KEY_QUERY].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The field " + std::string(KEY_QUERY) + " must contain a JSON object"); - } - else - { - std::unique_ptr handler(new QueryRetrieveHandler(context)); - - handler->SetModality(call.GetUriComponent("id", "")); - handler->SetLevel(StringToResourceType(request[KEY_LEVEL].asCString())); - - if (request.isMember(KEY_QUERY)) - { - std::map query; - SerializationToolbox::ReadMapOfTags(query, request, KEY_QUERY); - - for (std::map::const_iterator - it = query.begin(); it != query.end(); ++it) - { - handler->SetQuery(it->first, it->second); - } - } - - if (request.isMember(KEY_NORMALIZE)) - { - handler->SetFindNormalized(request[KEY_NORMALIZE].asBool()); - } - - AnswerQueryHandler(call, handler); - } - } - - - static void ListQueries(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::list queries; - context.GetQueryRetrieveArchive().List(queries); - - Json::Value result = Json::arrayValue; - for (std::list::const_iterator - it = queries.begin(); it != queries.end(); ++it) - { - result.append(*it); - } - - call.GetOutput().AnswerJson(result); - } - - - namespace - { - class QueryAccessor - { - private: - ServerContext& context_; - SharedArchive::Accessor accessor_; - QueryRetrieveHandler* handler_; - - public: - QueryAccessor(RestApiCall& call) : - context_(OrthancRestApi::GetContext(call)), - accessor_(context_.GetQueryRetrieveArchive(), call.GetUriComponent("id", "")), - handler_(NULL) - { - if (accessor_.IsValid()) - { - handler_ = &dynamic_cast(accessor_.GetItem()); - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - QueryRetrieveHandler& GetHandler() const - { - assert(handler_ != NULL); - return *handler_; - } - }; - - static void AnswerDicomMap(RestApiCall& call, - const DicomMap& value, - bool simplify) - { - Json::Value full = Json::objectValue; - FromDcmtkBridge::ToJson(full, value, simplify); - call.GetOutput().AnswerJson(full); - } - } - - - static void ListQueryAnswers(RestApiGetCall& call) - { - const bool expand = call.HasArgument("expand"); - const bool simplify = call.HasArgument("simplify"); - - QueryAccessor query(call); - size_t count = query.GetHandler().GetAnswersCount(); - - Json::Value result = Json::arrayValue; - for (size_t i = 0; i < count; i++) - { - if (expand) - { - // New in Orthanc 1.5.0 - DicomMap value; - query.GetHandler().GetAnswer(value, i); - - Json::Value json = Json::objectValue; - FromDcmtkBridge::ToJson(json, value, simplify); - - result.append(json); - } - else - { - result.append(boost::lexical_cast(i)); - } - } - - call.GetOutput().AnswerJson(result); - } - - - static void GetQueryOneAnswer(RestApiGetCall& call) - { - size_t index = boost::lexical_cast(call.GetUriComponent("index", "")); - - QueryAccessor query(call); - - DicomMap map; - query.GetHandler().GetAnswer(map, index); - - AnswerDicomMap(call, map, call.HasArgument("simplify")); - } - - - static void SubmitRetrieveJob(RestApiPostCall& call, - bool allAnswers, - size_t index) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string targetAet; - int timeout = -1; - - Json::Value body; - if (call.ParseJsonRequest(body)) - { - targetAet = Toolbox::GetJsonStringField(body, KEY_TARGET_AET, context.GetDefaultLocalApplicationEntityTitle()); - timeout = Toolbox::GetJsonIntegerField(body, KEY_TIMEOUT, -1); - } - else - { - body = Json::objectValue; - if (call.GetBodySize() > 0) - { - call.BodyToString(targetAet); - } - else - { - targetAet = context.GetDefaultLocalApplicationEntityTitle(); - } - } - - std::unique_ptr job(new DicomMoveScuJob(context)); - - { - QueryAccessor query(call); - job->SetTargetAet(targetAet); - job->SetLocalAet(query.GetHandler().GetLocalAet()); - job->SetRemoteModality(query.GetHandler().GetRemoteModality()); - - if (timeout >= 0) - { - // New in Orthanc 1.7.0 - job->SetTimeout(static_cast(timeout)); - } - - LOG(WARNING) << "Driving C-Move SCU on remote modality " - << query.GetHandler().GetRemoteModality().GetApplicationEntityTitle() - << " to target modality " << targetAet; - - if (allAnswers) - { - for (size_t i = 0; i < query.GetHandler().GetAnswersCount(); i++) - { - job->AddFindAnswer(query.GetHandler(), i); - } - } - else - { - job->AddFindAnswer(query.GetHandler(), index); - } - } - - OrthancRestApi::GetApi(call).SubmitCommandsJob - (call, job.release(), true /* synchronous by default */, body); - } - - - static void RetrieveOneAnswer(RestApiPostCall& call) - { - size_t index = boost::lexical_cast(call.GetUriComponent("index", "")); - SubmitRetrieveJob(call, false, index); - } - - - static void RetrieveAllAnswers(RestApiPostCall& call) - { - SubmitRetrieveJob(call, true, 0); - } - - - static void GetQueryArguments(RestApiGetCall& call) - { - QueryAccessor query(call); - AnswerDicomMap(call, query.GetHandler().GetQuery(), call.HasArgument("simplify")); - } - - - static void GetQueryLevel(RestApiGetCall& call) - { - QueryAccessor query(call); - call.GetOutput().AnswerBuffer(EnumerationToString(query.GetHandler().GetLevel()), MimeType_PlainText); - } - - - static void GetQueryModality(RestApiGetCall& call) - { - QueryAccessor query(call); - call.GetOutput().AnswerBuffer(query.GetHandler().GetModalitySymbolicName(), MimeType_PlainText); - } - - - static void DeleteQuery(RestApiDeleteCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - context.GetQueryRetrieveArchive().Remove(call.GetUriComponent("id", "")); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - static void ListQueryOperations(RestApiGetCall& call) - { - // Ensure that the query of interest does exist - QueryAccessor query(call); - - RestApi::AutoListChildren(call); - } - - - static void ListQueryAnswerOperations(RestApiGetCall& call) - { - // Ensure that the query of interest does exist - QueryAccessor query(call); - - // Ensure that the answer of interest does exist - size_t index = boost::lexical_cast(call.GetUriComponent("index", "")); - - DicomMap map; - query.GetHandler().GetAnswer(map, index); - - Json::Value answer = Json::arrayValue; - answer.append("content"); - answer.append("retrieve"); - - switch (query.GetHandler().GetLevel()) - { - case ResourceType_Patient: - answer.append("query-study"); - - case ResourceType_Study: - answer.append("query-series"); - - case ResourceType_Series: - answer.append("query-instances"); - break; - - default: - break; - } - - call.GetOutput().AnswerJson(answer); - } - - - template - static void QueryAnswerChildren(RestApiPostCall& call) - { - // New in Orthanc 1.5.0 - assert(CHILDREN_LEVEL == ResourceType_Study || - CHILDREN_LEVEL == ResourceType_Series || - CHILDREN_LEVEL == ResourceType_Instance); - - ServerContext& context = OrthancRestApi::GetContext(call); - - std::unique_ptr handler(new QueryRetrieveHandler(context)); - - { - const QueryAccessor parent(call); - const ResourceType level = parent.GetHandler().GetLevel(); - - const size_t index = boost::lexical_cast(call.GetUriComponent("index", "")); - - Json::Value request; - - if (index >= parent.GetHandler().GetAnswersCount()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else if (CHILDREN_LEVEL == ResourceType_Study && - level != ResourceType_Patient) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else if (CHILDREN_LEVEL == ResourceType_Series && - level != ResourceType_Patient && - level != ResourceType_Study) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else if (CHILDREN_LEVEL == ResourceType_Instance && - level != ResourceType_Patient && - level != ResourceType_Study && - level != ResourceType_Series) - { - throw OrthancException(ErrorCode_UnknownResource); - } - else if (!call.ParseJsonRequest(request)) - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON object"); - } - else - { - handler->SetFindNormalized(parent.GetHandler().IsFindNormalized()); - handler->SetModality(parent.GetHandler().GetModalitySymbolicName()); - handler->SetLevel(CHILDREN_LEVEL); - - if (request.isMember(KEY_QUERY)) - { - std::map query; - SerializationToolbox::ReadMapOfTags(query, request, KEY_QUERY); - - for (std::map::const_iterator - it = query.begin(); it != query.end(); ++it) - { - handler->SetQuery(it->first, it->second); - } - } - - DicomMap answer; - parent.GetHandler().GetAnswer(answer, index); - - // This switch-case mimics "DicomControlUserConnection::Move()" - switch (parent.GetHandler().GetLevel()) - { - case ResourceType_Patient: - handler->CopyStringTag(answer, DICOM_TAG_PATIENT_ID); - break; - - case ResourceType_Study: - handler->CopyStringTag(answer, DICOM_TAG_STUDY_INSTANCE_UID); - break; - - case ResourceType_Series: - handler->CopyStringTag(answer, DICOM_TAG_STUDY_INSTANCE_UID); - handler->CopyStringTag(answer, DICOM_TAG_SERIES_INSTANCE_UID); - break; - - case ResourceType_Instance: - handler->CopyStringTag(answer, DICOM_TAG_STUDY_INSTANCE_UID); - handler->CopyStringTag(answer, DICOM_TAG_SERIES_INSTANCE_UID); - handler->CopyStringTag(answer, DICOM_TAG_SOP_INSTANCE_UID); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - } - - AnswerQueryHandler(call, handler); - } - - - - /*************************************************************************** - * DICOM C-Store SCU - ***************************************************************************/ - - static void GetInstancesToExport(Json::Value& otherArguments, - SetOfInstancesJob& job, - const std::string& remote, - RestApiPostCall& call) - { - otherArguments = Json::objectValue; - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value request; - if (Toolbox::IsSHA1(call.GetBodyData(), call.GetBodySize())) - { - std::string s; - call.BodyToString(s); - - // This is for compatibility with Orthanc <= 0.5.1. - request = Json::arrayValue; - request.append(Toolbox::StripSpaces(s)); - } - else if (!call.ParseJsonRequest(request)) - { - // Bad JSON request - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON value"); - } - - if (request.isString()) - { - std::string item = request.asString(); - request = Json::arrayValue; - request.append(item); - } - else if (!request.isArray() && - !request.isObject()) - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON object, or a JSON array of strings"); - } - - const Json::Value* resources; - if (request.isArray()) - { - resources = &request; - } - else - { - if (request.type() != Json::objectValue || - !request.isMember(KEY_RESOURCES)) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Missing field in JSON: \"" + std::string(KEY_RESOURCES) + "\""); - } - - resources = &request[KEY_RESOURCES]; - if (!resources->isArray()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "JSON field \"" + std::string(KEY_RESOURCES) + "\" must contain an array"); - } - - // Copy the remaining arguments - Json::Value::Members members = request.getMemberNames(); - for (Json::Value::ArrayIndex i = 0; i < members.size(); i++) - { - otherArguments[members[i]] = request[members[i]]; - } - } - - bool logExportedResources; - - { - OrthancConfiguration::ReaderLock lock; - logExportedResources = lock.GetConfiguration().GetBooleanParameter("LogExportedResources", false); - } - - for (Json::Value::ArrayIndex i = 0; i < resources->size(); i++) - { - if (!(*resources) [i].isString()) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Resources to be exported must be specified as a JSON array of strings"); - } - - std::string stripped = Toolbox::StripSpaces((*resources) [i].asString()); - if (!Toolbox::IsSHA1(stripped)) - { - throw OrthancException(ErrorCode_BadFileFormat, - "This string is not a valid Orthanc identifier: " + stripped); - } - - job.AddParentResource(stripped); // New in Orthanc 1.5.7 - - context.AddChildInstances(job, stripped); - - if (logExportedResources) - { - context.GetIndex().LogExportedResource(stripped, remote); - } - } - } - - - static void DicomStore(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string remote = call.GetUriComponent("id", ""); - - Json::Value request; - std::unique_ptr job(new DicomModalityStoreJob(context)); - - GetInstancesToExport(request, *job, remote, call); - - std::string localAet = Toolbox::GetJsonStringField - (request, KEY_LOCAL_AET, context.GetDefaultLocalApplicationEntityTitle()); - std::string moveOriginatorAET = Toolbox::GetJsonStringField - (request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle()); - int moveOriginatorID = Toolbox::GetJsonIntegerField - (request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */); - - job->SetLocalAet(localAet); - job->SetRemoteModality(MyGetModalityUsingSymbolicName(remote)); - - if (moveOriginatorID != 0) - { - job->SetMoveOriginator(moveOriginatorAET, moveOriginatorID); - } - - // New in Orthanc 1.6.0 - if (Toolbox::GetJsonBooleanField(request, "StorageCommitment", false)) - { - job->EnableStorageCommitment(true); - } - - // New in Orthanc 1.7.0 - if (request.isMember(KEY_TIMEOUT)) - { - job->SetTimeout(SerializationToolbox::ReadUnsignedInteger(request, KEY_TIMEOUT)); - } - - OrthancRestApi::GetApi(call).SubmitCommandsJob - (call, job.release(), true /* synchronous by default */, request); - } - - - static void DicomStoreStraight(RestApiPostCall& call) - { - Json::Value body = Json::objectValue; // No body - DicomStoreUserConnection connection(GetAssociationParameters(call, body)); - - std::string sopClassUid, sopInstanceUid; - connection.Store(sopClassUid, sopInstanceUid, call.GetBodyData(), - call.GetBodySize(), false /* Not a C-MOVE */, "", 0); - - Json::Value answer = Json::objectValue; - answer[SOP_CLASS_UID] = sopClassUid; - answer[SOP_INSTANCE_UID] = sopInstanceUid; - - call.GetOutput().AnswerJson(answer); - } - - - /*************************************************************************** - * DICOM C-Move SCU - ***************************************************************************/ - - static void DicomMove(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value request; - - if (!call.ParseJsonRequest(request) || - request.type() != Json::objectValue || - !request.isMember(KEY_RESOURCES) || - !request.isMember(KEY_LEVEL) || - request[KEY_RESOURCES].type() != Json::arrayValue || - request[KEY_LEVEL].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON body containing fields " + - std::string(KEY_RESOURCES) + " and " + std::string(KEY_LEVEL)); - } - - ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); - - std::string localAet = Toolbox::GetJsonStringField - (request, KEY_LOCAL_AET, context.GetDefaultLocalApplicationEntityTitle()); - std::string targetAet = Toolbox::GetJsonStringField - (request, KEY_TARGET_AET, context.GetDefaultLocalApplicationEntityTitle()); - - const RemoteModalityParameters source = - MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); - - DicomAssociationParameters params(localAet, source); - InjectAssociationTimeout(params, request); - - DicomControlUserConnection connection(params); - - for (Json::Value::ArrayIndex i = 0; i < request[KEY_RESOURCES].size(); i++) - { - DicomMap resource; - FromDcmtkBridge::FromJson(resource, request[KEY_RESOURCES][i]); - - connection.Move(targetAet, level, resource); - } - - // Move has succeeded - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - - - - /*************************************************************************** - * Orthanc Peers => Store client - ***************************************************************************/ - - static bool IsExistingPeer(const OrthancRestApi::SetOfStrings& peers, - const std::string& id) - { - return peers.find(id) != peers.end(); - } - - static void ListPeers(RestApiGetCall& call) - { - OrthancConfiguration::ReaderLock lock; - - OrthancRestApi::SetOfStrings peers; - lock.GetConfiguration().GetListOfOrthancPeers(peers); - - if (call.HasArgument("expand")) - { - Json::Value result = Json::objectValue; - for (OrthancRestApi::SetOfStrings::const_iterator - it = peers.begin(); it != peers.end(); ++it) - { - WebServiceParameters peer; - - if (lock.GetConfiguration().LookupOrthancPeer(peer, *it)) - { - Json::Value info; - peer.FormatPublic(info); - result[*it] = info; - } - } - call.GetOutput().AnswerJson(result); - } - else // if expand is not present, keep backward compatibility and return an array of peers - { - Json::Value result = Json::arrayValue; - for (OrthancRestApi::SetOfStrings::const_iterator - it = peers.begin(); it != peers.end(); ++it) - { - result.append(*it); - } - - call.GetOutput().AnswerJson(result); - } - } - - static void ListPeerOperations(RestApiGetCall& call) - { - OrthancConfiguration::ReaderLock lock; - - OrthancRestApi::SetOfStrings peers; - lock.GetConfiguration().GetListOfOrthancPeers(peers); - - std::string id = call.GetUriComponent("id", ""); - if (IsExistingPeer(peers, id)) - { - RestApi::AutoListChildren(call); - } - } - - static void PeerStore(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string remote = call.GetUriComponent("id", ""); - - Json::Value request; - std::unique_ptr job(new OrthancPeerStoreJob(context)); - - GetInstancesToExport(request, *job, remote, call); - - static const char* TRANSCODE = "Transcode"; - if (request.type() == Json::objectValue && - request.isMember(TRANSCODE)) - { - job->SetTranscode(SerializationToolbox::ReadString(request, TRANSCODE)); - } - - { - OrthancConfiguration::ReaderLock lock; - - WebServiceParameters peer; - if (lock.GetConfiguration().LookupOrthancPeer(peer, remote)) - { - job->SetPeer(peer); - } - else - { - throw OrthancException(ErrorCode_UnknownResource, - "No peer with symbolic name: " + remote); - } - } - - OrthancRestApi::GetApi(call).SubmitCommandsJob - (call, job.release(), true /* synchronous by default */, request); - } - - static void PeerSystem(RestApiGetCall& call) - { - std::string remote = call.GetUriComponent("id", ""); - - OrthancConfiguration::ReaderLock lock; - - WebServiceParameters peer; - if (lock.GetConfiguration().LookupOrthancPeer(peer, remote)) - { - HttpClient client(peer, "system"); - std::string answer; - - client.SetMethod(HttpMethod_Get); - - if (!client.Apply(answer)) - { - LOG(ERROR) << "Unable to get the system info from remote Orthanc peer: " << peer.GetUrl(); - call.GetOutput().SignalError(client.GetLastStatus()); - return; - } - - call.GetOutput().AnswerBuffer(answer, MimeType_Json); - } - else - { - throw OrthancException(ErrorCode_UnknownResource, - "No peer with symbolic name: " + remote); - } - } - - // DICOM bridge ------------------------------------------------------------- - - static bool IsExistingModality(const OrthancRestApi::SetOfStrings& modalities, - const std::string& id) - { - return modalities.find(id) != modalities.end(); - } - - static void ListModalities(RestApiGetCall& call) - { - OrthancConfiguration::ReaderLock lock; - - OrthancRestApi::SetOfStrings modalities; - lock.GetConfiguration().GetListOfDicomModalities(modalities); - - if (call.HasArgument("expand")) - { - Json::Value result = Json::objectValue; - for (OrthancRestApi::SetOfStrings::const_iterator - it = modalities.begin(); it != modalities.end(); ++it) - { - const RemoteModalityParameters& remote = lock.GetConfiguration().GetModalityUsingSymbolicName(*it); - - Json::Value info; - remote.Serialize(info, true /* force advanced format */); - result[*it] = info; - } - call.GetOutput().AnswerJson(result); - } - else // if expand is not present, keep backward compatibility and return an array of modalities ids - { - Json::Value result = Json::arrayValue; - for (OrthancRestApi::SetOfStrings::const_iterator - it = modalities.begin(); it != modalities.end(); ++it) - { - result.append(*it); - } - call.GetOutput().AnswerJson(result); - } - } - - - static void ListModalityOperations(RestApiGetCall& call) - { - OrthancConfiguration::ReaderLock lock; - - OrthancRestApi::SetOfStrings modalities; - lock.GetConfiguration().GetListOfDicomModalities(modalities); - - std::string id = call.GetUriComponent("id", ""); - if (IsExistingModality(modalities, id)) - { - RestApi::AutoListChildren(call); - } - } - - - static void UpdateModality(RestApiPutCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value json; - if (call.ParseJsonRequest(json)) - { - RemoteModalityParameters modality; - modality.Unserialize(json); - - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().UpdateModality(call.GetUriComponent("id", ""), modality); - } - - context.SignalUpdatedModalities(); - - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - } - - - static void DeleteModality(RestApiDeleteCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().RemoveModality(call.GetUriComponent("id", "")); - } - - context.SignalUpdatedModalities(); - - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - static void UpdatePeer(RestApiPutCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value json; - if (call.ParseJsonRequest(json)) - { - WebServiceParameters peer; - peer.Unserialize(json); - - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().UpdatePeer(call.GetUriComponent("id", ""), peer); - } - - context.SignalUpdatedPeers(); - - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - } - - - static void DeletePeer(RestApiDeleteCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().RemovePeer(call.GetUriComponent("id", "")); - } - - context.SignalUpdatedPeers(); - - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - static void DicomFindWorklist(RestApiPostCall& call) - { - Json::Value json; - if (call.ParseJsonRequest(json)) - { - std::unique_ptr query - (ParsedDicomFile::CreateFromJson(json, static_cast(0), - "" /* no private creator */)); - - DicomFindAnswers answers(true); - - { - DicomControlUserConnection connection(GetAssociationParameters(call, json)); - connection.FindWorklist(answers, *query); - } - - Json::Value result; - answers.ToJson(result, true); - call.GetOutput().AnswerJson(result); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, "Must provide a JSON object"); - } - } - - - // Storage commitment SCU --------------------------------------------------- - - static void StorageCommitmentScu(RestApiPostCall& call) - { - static const char* const ORTHANC_RESOURCES = "Resources"; - static const char* const DICOM_INSTANCES = "DicomInstances"; - - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value json; - if (!call.ParseJsonRequest(json) || - json.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Must provide a JSON object with a list of resources"); - } - else if (!json.isMember(ORTHANC_RESOURCES) && - !json.isMember(DICOM_INSTANCES)) - { - throw OrthancException(ErrorCode_BadFileFormat, - "Empty storage commitment request, one of these fields is mandatory: \"" + - std::string(ORTHANC_RESOURCES) + "\" or \"" + std::string(DICOM_INSTANCES) + "\""); - } - else - { - std::list sopClassUids, sopInstanceUids; - - if (json.isMember(ORTHANC_RESOURCES)) - { - const Json::Value& resources = json[ORTHANC_RESOURCES]; - - if (resources.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The \"" + std::string(ORTHANC_RESOURCES) + - "\" field must provide an array of Orthanc resources"); - } - else - { - for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) - { - if (resources[i].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The \"" + std::string(ORTHANC_RESOURCES) + - "\" field must provide an array of strings, found: " + resources[i].toStyledString()); - } - - std::list instances; - context.GetIndex().GetChildInstances(instances, resources[i].asString()); - - for (std::list::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - std::string sopClassUid, sopInstanceUid; - DicomMap tags; - if (context.LookupOrReconstructMetadata(sopClassUid, *it, MetadataType_Instance_SopClassUid) && - context.GetIndex().GetAllMainDicomTags(tags, *it) && - tags.LookupStringValue(sopInstanceUid, DICOM_TAG_SOP_INSTANCE_UID, false)) - { - sopClassUids.push_back(sopClassUid); - sopInstanceUids.push_back(sopInstanceUid); - } - else - { - throw OrthancException(ErrorCode_InternalError, - "Cannot retrieve SOP Class/Instance UID of Orthanc instance: " + *it); - } - } - } - } - } - - if (json.isMember(DICOM_INSTANCES)) - { - const Json::Value& instances = json[DICOM_INSTANCES]; - - if (instances.type() != Json::arrayValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "The \"" + std::string(DICOM_INSTANCES) + - "\" field must provide an array of DICOM instances"); - } - else - { - for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++) - { - if (instances[i].type() == Json::arrayValue) - { - if (instances[i].size() != 2 || - instances[i][0].type() != Json::stringValue || - instances[i][1].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "An instance entry must provide an array with 2 strings: " - "SOP Class UID and SOP Instance UID"); - } - else - { - sopClassUids.push_back(instances[i][0].asString()); - sopInstanceUids.push_back(instances[i][1].asString()); - } - } - else if (instances[i].type() == Json::objectValue) - { - if (!instances[i].isMember(SOP_CLASS_UID) || - !instances[i].isMember(SOP_INSTANCE_UID) || - instances[i][SOP_CLASS_UID].type() != Json::stringValue || - instances[i][SOP_INSTANCE_UID].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat, - "An instance entry must provide an object with 2 string fiels: " - "\"" + std::string(SOP_CLASS_UID) + "\" and \"" + - std::string(SOP_INSTANCE_UID)); - } - else - { - sopClassUids.push_back(instances[i][SOP_CLASS_UID].asString()); - sopInstanceUids.push_back(instances[i][SOP_INSTANCE_UID].asString()); - } - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "JSON array or object is expected to specify one " - "instance to be queried, found: " + instances[i].toStyledString()); - } - } - } - } - - if (sopClassUids.size() != sopInstanceUids.size()) - { - throw OrthancException(ErrorCode_InternalError); - } - - const std::string transactionUid = Toolbox::GenerateDicomPrivateUniqueIdentifier(); - - if (sopClassUids.empty()) - { - LOG(WARNING) << "Issuing an outgoing storage commitment request that is empty: " << transactionUid; - } - - { - const RemoteModalityParameters remote = - MyGetModalityUsingSymbolicName(call.GetUriComponent("id", "")); - - const std::string& remoteAet = remote.GetApplicationEntityTitle(); - const std::string& localAet = context.GetDefaultLocalApplicationEntityTitle(); - - // Create a "pending" storage commitment report BEFORE the - // actual SCU call in order to avoid race conditions - context.GetStorageCommitmentReports().Store( - transactionUid, new StorageCommitmentReports::Report(remoteAet)); - - DicomAssociationParameters parameters(localAet, remote); - - std::vector a(sopClassUids.begin(), sopClassUids.end()); - std::vector b(sopInstanceUids.begin(), sopInstanceUids.end()); - DicomAssociation::RequestStorageCommitment(parameters, transactionUid, a, b); - } - - Json::Value result = Json::objectValue; - result["ID"] = transactionUid; - result["Path"] = "/storage-commitment/" + transactionUid; - call.GetOutput().AnswerJson(result); - } - } - - - static void GetStorageCommitmentReport(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - const std::string& transactionUid = call.GetUriComponent("id", ""); - - { - StorageCommitmentReports::Accessor accessor( - context.GetStorageCommitmentReports(), transactionUid); - - if (accessor.IsValid()) - { - Json::Value json; - accessor.GetReport().Format(json); - call.GetOutput().AnswerJson(json); - } - else - { - throw OrthancException(ErrorCode_InexistentItem, - "No storage commitment transaction with UID: " + transactionUid); - } - } - } - - - static void RemoveAfterStorageCommitment(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - const std::string& transactionUid = call.GetUriComponent("id", ""); - - { - StorageCommitmentReports::Accessor accessor( - context.GetStorageCommitmentReports(), transactionUid); - - if (!accessor.IsValid()) - { - throw OrthancException(ErrorCode_InexistentItem, - "No storage commitment transaction with UID: " + transactionUid); - } - else if (accessor.GetReport().GetStatus() != StorageCommitmentReports::Report::Status_Success) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Cannot remove DICOM instances after failure " - "in storage commitment transaction: " + transactionUid); - } - else - { - std::vector sopInstanceUids; - accessor.GetReport().GetSuccessSopInstanceUids(sopInstanceUids); - - for (size_t i = 0; i < sopInstanceUids.size(); i++) - { - std::vector orthancId; - context.GetIndex().LookupIdentifierExact( - orthancId, ResourceType_Instance, DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUids[i]); - - for (size_t j = 0; j < orthancId.size(); j++) - { - LOG(INFO) << "Storage commitment - Removing SOP instance UID / Orthanc ID: " - << sopInstanceUids[i] << " / " << orthancId[j]; - - Json::Value tmp; - context.GetIndex().DeleteResource(tmp, orthancId[j], ResourceType_Instance); - } - } - - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - } - } - - - void OrthancRestApi::RegisterModalities() - { - Register("/modalities", ListModalities); - Register("/modalities/{id}", ListModalityOperations); - Register("/modalities/{id}", UpdateModality); - Register("/modalities/{id}", DeleteModality); - Register("/modalities/{id}/echo", DicomEcho); - Register("/modalities/{id}/find-patient", DicomFindPatient); - Register("/modalities/{id}/find-study", DicomFindStudy); - Register("/modalities/{id}/find-series", DicomFindSeries); - Register("/modalities/{id}/find-instance", DicomFindInstance); - Register("/modalities/{id}/find", DicomFind); - Register("/modalities/{id}/store", DicomStore); - Register("/modalities/{id}/store-straight", DicomStoreStraight); // New in 1.6.1 - Register("/modalities/{id}/move", DicomMove); - - // For Query/Retrieve - Register("/modalities/{id}/query", DicomQuery); - Register("/queries", ListQueries); - Register("/queries/{id}", DeleteQuery); - Register("/queries/{id}", ListQueryOperations); - Register("/queries/{id}/answers", ListQueryAnswers); - Register("/queries/{id}/answers/{index}", ListQueryAnswerOperations); - Register("/queries/{id}/answers/{index}/content", GetQueryOneAnswer); - Register("/queries/{id}/answers/{index}/retrieve", RetrieveOneAnswer); - Register("/queries/{id}/answers/{index}/query-instances", - QueryAnswerChildren); - Register("/queries/{id}/answers/{index}/query-series", - QueryAnswerChildren); - Register("/queries/{id}/answers/{index}/query-studies", - QueryAnswerChildren); - Register("/queries/{id}/level", GetQueryLevel); - Register("/queries/{id}/modality", GetQueryModality); - Register("/queries/{id}/query", GetQueryArguments); - Register("/queries/{id}/retrieve", RetrieveAllAnswers); - - Register("/peers", ListPeers); - Register("/peers/{id}", ListPeerOperations); - Register("/peers/{id}", UpdatePeer); - Register("/peers/{id}", DeletePeer); - Register("/peers/{id}/store", PeerStore); - Register("/peers/{id}/system", PeerSystem); - - Register("/modalities/{id}/find-worklist", DicomFindWorklist); - - // Storage commitment - Register("/modalities/{id}/storage-commitment", StorageCommitmentScu); - Register("/storage-commitment/{id}", GetStorageCommitmentReport); - Register("/storage-commitment/{id}/remove", RemoveAfterStorageCommitment); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestResources.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestResources.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestResources.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2165 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../../Core/Compression/GzipCompressor.h" -#include "../../Core/DicomFormat/DicomImageInformation.h" -#include "../../Core/DicomParsing/DicomWebJsonVisitor.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/DicomParsing/Internals/DicomImageDecoder.h" -#include "../../Core/HttpServer/HttpContentNegociation.h" -#include "../../Core/Images/Image.h" -#include "../../Core/Images/ImageProcessing.h" -#include "../../Core/Logging.h" -#include "../../Core/MultiThreading/Semaphore.h" -#include "../OrthancConfiguration.h" -#include "../Search/DatabaseLookup.h" -#include "../ServerContext.h" -#include "../ServerToolbox.h" -#include "../SliceOrdering.h" - -#include "../../Plugins/Engine/OrthancPlugins.h" - -// This "include" is mandatory for Release builds using Linux Standard Base -#include - - -/** - * This semaphore is used to limit the number of concurrent HTTP - * requests on CPU-intensive routes of the REST API, in order to - * prevent exhaustion of resources (new in Orthanc 1.7.0). - **/ -static Orthanc::Semaphore throttlingSemaphore_(4); // TODO => PARAMETER? - - -namespace Orthanc -{ - static void AnswerDicomAsJson(RestApiCall& call, - const Json::Value& dicom, - DicomToJsonFormat mode) - { - if (mode != DicomToJsonFormat_Full) - { - Json::Value simplified; - ServerToolbox::SimplifyTags(simplified, dicom, mode); - call.GetOutput().AnswerJson(simplified); - } - else - { - call.GetOutput().AnswerJson(dicom); - } - } - - - static DicomToJsonFormat GetDicomFormat(const RestApiGetCall& call) - { - if (call.HasArgument("simplify")) - { - return DicomToJsonFormat_Human; - } - else if (call.HasArgument("short")) - { - return DicomToJsonFormat_Short; - } - else - { - return DicomToJsonFormat_Full; - } - } - - - static void AnswerDicomAsJson(RestApiGetCall& call, - const Json::Value& dicom) - { - AnswerDicomAsJson(call, dicom, GetDicomFormat(call)); - } - - - static void ParseSetOfTags(std::set& target, - const RestApiGetCall& call, - const std::string& argument) - { - target.clear(); - - if (call.HasArgument(argument)) - { - std::vector tags; - Toolbox::TokenizeString(tags, call.GetArgument(argument, ""), ','); - - for (size_t i = 0; i < tags.size(); i++) - { - target.insert(FromDcmtkBridge::ParseTag(tags[i])); - } - } - } - - - // List all the patients, studies, series or instances ---------------------- - - static void AnswerListOfResources(RestApiOutput& output, - ServerIndex& index, - const std::list& resources, - ResourceType level, - bool expand) - { - Json::Value answer = Json::arrayValue; - - for (std::list::const_iterator - resource = resources.begin(); resource != resources.end(); ++resource) - { - if (expand) - { - Json::Value item; - if (index.LookupResource(item, *resource, level)) - { - answer.append(item); - } - } - else - { - answer.append(*resource); - } - } - - output.AnswerJson(answer); - } - - - template - static void ListResources(RestApiGetCall& call) - { - ServerIndex& index = OrthancRestApi::GetIndex(call); - - std::list result; - - if (call.HasArgument("limit") || - call.HasArgument("since")) - { - if (!call.HasArgument("limit")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"limit\" argument for GET request against: " + - call.FlattenUri()); - } - - if (!call.HasArgument("since")) - { - throw OrthancException(ErrorCode_BadRequest, - "Missing \"since\" argument for GET request against: " + - call.FlattenUri()); - } - - size_t since = boost::lexical_cast(call.GetArgument("since", "")); - size_t limit = boost::lexical_cast(call.GetArgument("limit", "")); - index.GetAllUuids(result, resourceType, since, limit); - } - else - { - index.GetAllUuids(result, resourceType); - } - - - AnswerListOfResources(call.GetOutput(), index, result, resourceType, call.HasArgument("expand")); - } - - template - static void GetSingleResource(RestApiGetCall& call) - { - Json::Value result; - if (OrthancRestApi::GetIndex(call).LookupResource(result, call.GetUriComponent("id", ""), resourceType)) - { - call.GetOutput().AnswerJson(result); - } - } - - template - static void DeleteSingleResource(RestApiDeleteCall& call) - { - Json::Value result; - if (OrthancRestApi::GetContext(call).DeleteResource(result, call.GetUriComponent("id", ""), resourceType)) - { - call.GetOutput().AnswerJson(result); - } - } - - - // Get information about a single patient ----------------------------------- - - static void IsProtectedPatient(RestApiGetCall& call) - { - std::string publicId = call.GetUriComponent("id", ""); - bool isProtected = OrthancRestApi::GetIndex(call).IsProtectedPatient(publicId); - call.GetOutput().AnswerBuffer(isProtected ? "1" : "0", MimeType_PlainText); - } - - - static void SetPatientProtection(RestApiPutCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string publicId = call.GetUriComponent("id", ""); - - std::string body; - call.BodyToString(body); - body = Toolbox::StripSpaces(body); - - if (body == "0") - { - context.GetIndex().SetProtectedPatient(publicId, false); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - else if (body == "1") - { - context.GetIndex().SetProtectedPatient(publicId, true); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - else - { - // Bad request - } - } - - - // Get information about a single instance ---------------------------------- - - static void GetInstanceFile(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string publicId = call.GetUriComponent("id", ""); - - IHttpHandler::Arguments::const_iterator accept = call.GetHttpHeaders().find("accept"); - if (accept != call.GetHttpHeaders().end()) - { - // New in Orthanc 1.5.4 - try - { - MimeType mime = StringToMimeType(accept->second.c_str()); - - if (mime == MimeType_DicomWebJson || - mime == MimeType_DicomWebXml) - { - DicomWebJsonVisitor visitor; - - { - ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), publicId); - locker.GetDicom().Apply(visitor); - } - - if (mime == MimeType_DicomWebJson) - { - std::string s = visitor.GetResult().toStyledString(); - call.GetOutput().AnswerBuffer(s, MimeType_DicomWebJson); - } - else - { - std::string xml; - visitor.FormatXml(xml); - call.GetOutput().AnswerBuffer(xml, MimeType_DicomWebXml); - } - - return; - } - } - catch (OrthancException&) - { - } - } - - context.AnswerAttachment(call.GetOutput(), publicId, FileContentType_Dicom); - } - - - static void ExportInstanceFile(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string publicId = call.GetUriComponent("id", ""); - - std::string dicom; - context.ReadDicom(dicom, publicId); - - std::string target; - call.BodyToString(target); - SystemToolbox::WriteFile(dicom, target); - - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - - - template - static void GetInstanceTags(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string publicId = call.GetUriComponent("id", ""); - - std::set ignoreTagLength; - ParseSetOfTags(ignoreTagLength, call, "ignore-length"); - - if (format != DicomToJsonFormat_Full || - !ignoreTagLength.empty()) - { - Json::Value full; - context.ReadDicomAsJson(full, publicId, ignoreTagLength); - AnswerDicomAsJson(call, full, format); - } - else - { - // This path allows to avoid the JSON decoding if no - // simplification is asked, and if no "ignore-length" argument - // is present - std::string full; - context.ReadDicomAsJson(full, publicId); - call.GetOutput().AnswerBuffer(full, MimeType_Json); - } - } - - - static void GetInstanceTagsBis(RestApiGetCall& call) - { - switch (GetDicomFormat(call)) - { - case DicomToJsonFormat_Human: - GetInstanceTags(call); - break; - - case DicomToJsonFormat_Short: - GetInstanceTags(call); - break; - - case DicomToJsonFormat_Full: - GetInstanceTags(call); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - static void ListFrames(RestApiGetCall& call) - { - std::string publicId = call.GetUriComponent("id", ""); - - unsigned int numberOfFrames; - - { - ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), publicId); - numberOfFrames = locker.GetDicom().GetFramesCount(); - } - - Json::Value result = Json::arrayValue; - for (unsigned int i = 0; i < numberOfFrames; i++) - { - result.append(i); - } - - call.GetOutput().AnswerJson(result); - } - - - namespace - { - class ImageToEncode - { - private: - std::unique_ptr& image_; - ImageExtractionMode mode_; - bool invert_; - MimeType format_; - std::string answer_; - - public: - ImageToEncode(std::unique_ptr& image, - ImageExtractionMode mode, - bool invert) : - image_(image), - mode_(mode), - invert_(invert) - { - } - - void Answer(RestApiOutput& output) - { - output.AnswerBuffer(answer_, format_); - } - - void EncodeUsingPng() - { - format_ = MimeType_Png; - DicomImageDecoder::ExtractPngImage(answer_, image_, mode_, invert_); - } - - void EncodeUsingPam() - { - format_ = MimeType_Pam; - DicomImageDecoder::ExtractPamImage(answer_, image_, mode_, invert_); - } - - void EncodeUsingJpeg(uint8_t quality) - { - format_ = MimeType_Jpeg; - DicomImageDecoder::ExtractJpegImage(answer_, image_, mode_, invert_, quality); - } - }; - - class EncodePng : public HttpContentNegociation::IHandler - { - private: - ImageToEncode& image_; - - public: - EncodePng(ImageToEncode& image) : image_(image) - { - } - - virtual void Handle(const std::string& type, - const std::string& subtype) - { - assert(type == "image"); - assert(subtype == "png"); - image_.EncodeUsingPng(); - } - }; - - class EncodePam : public HttpContentNegociation::IHandler - { - private: - ImageToEncode& image_; - - public: - EncodePam(ImageToEncode& image) : image_(image) - { - } - - virtual void Handle(const std::string& type, - const std::string& subtype) - { - assert(type == "image"); - assert(subtype == "x-portable-arbitrarymap"); - image_.EncodeUsingPam(); - } - }; - - class EncodeJpeg : public HttpContentNegociation::IHandler - { - private: - ImageToEncode& image_; - unsigned int quality_; - - public: - EncodeJpeg(ImageToEncode& image, - const RestApiGetCall& call) : - image_(image) - { - std::string v = call.GetArgument("quality", "90" /* default JPEG quality */); - bool ok = false; - - try - { - quality_ = boost::lexical_cast(v); - ok = (quality_ >= 1 && quality_ <= 100); - } - catch (boost::bad_lexical_cast&) - { - } - - if (!ok) - { - throw OrthancException( - ErrorCode_BadRequest, - "Bad quality for a JPEG encoding (must be a number between 0 and 100): " + v); - } - } - - virtual void Handle(const std::string& type, - const std::string& subtype) - { - assert(type == "image"); - assert(subtype == "jpeg"); - image_.EncodeUsingJpeg(quality_); - } - }; - } - - - namespace - { - class IDecodedFrameHandler : public boost::noncopyable - { - public: - virtual ~IDecodedFrameHandler() - { - } - - virtual void Handle(RestApiGetCall& call, - std::unique_ptr& decoded, - const DicomMap& dicom) = 0; - - virtual bool RequiresDicomTags() const = 0; - - static void Apply(RestApiGetCall& call, - IDecodedFrameHandler& handler) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string frameId = call.GetUriComponent("frame", "0"); - - unsigned int frame; - try - { - frame = boost::lexical_cast(frameId); - } - catch (boost::bad_lexical_cast&) - { - return; - } - - DicomMap dicom; - std::unique_ptr decoded; - - try - { - std::string publicId = call.GetUriComponent("id", ""); - - decoded.reset(context.DecodeDicomFrame(publicId, frame)); - - if (decoded.get() == NULL) - { - throw OrthancException(ErrorCode_NotImplemented, - "Cannot decode DICOM instance with ID: " + publicId); - } - - if (handler.RequiresDicomTags()) - { - /** - * Retrieve a summary of the DICOM tags, which is - * necessary to deal with MONOCHROME1 photometric - * interpretation, and with windowing parameters. - **/ - ServerContext::DicomCacheLocker locker(context, publicId); - locker.GetDicom().ExtractDicomSummary(dicom); - } - } - catch (OrthancException& e) - { - if (e.GetErrorCode() == ErrorCode_ParameterOutOfRange || - e.GetErrorCode() == ErrorCode_UnknownResource) - { - // The frame number is out of the range for this DICOM - // instance, the resource is not existent - } - else - { - std::string root = ""; - for (size_t i = 1; i < call.GetFullUri().size(); i++) - { - root += "../"; - } - - call.GetOutput().Redirect(root + "app/images/unsupported.png"); - } - return; - } - - handler.Handle(call, decoded, dicom); - } - - - static void DefaultHandler(RestApiGetCall& call, - std::unique_ptr& decoded, - ImageExtractionMode mode, - bool invert) - { - ImageToEncode image(decoded, mode, invert); - - HttpContentNegociation negociation; - EncodePng png(image); - negociation.Register(MIME_PNG, png); - - EncodeJpeg jpeg(image, call); - negociation.Register(MIME_JPEG, jpeg); - - EncodePam pam(image); - negociation.Register(MIME_PAM, pam); - - if (negociation.Apply(call.GetHttpHeaders())) - { - image.Answer(call.GetOutput()); - } - } - }; - - - class GetImageHandler : public IDecodedFrameHandler - { - private: - ImageExtractionMode mode_; - - public: - GetImageHandler(ImageExtractionMode mode) : - mode_(mode) - { - } - - virtual void Handle(RestApiGetCall& call, - std::unique_ptr& decoded, - const DicomMap& dicom) ORTHANC_OVERRIDE - { - bool invert = false; - - if (mode_ == ImageExtractionMode_Preview) - { - DicomImageInformation info(dicom); - invert = (info.GetPhotometricInterpretation() == PhotometricInterpretation_Monochrome1); - } - - DefaultHandler(call, decoded, mode_, invert); - } - - virtual bool RequiresDicomTags() const ORTHANC_OVERRIDE - { - return mode_ == ImageExtractionMode_Preview; - } - }; - - - class RenderedFrameHandler : public IDecodedFrameHandler - { - private: - static void GetDicomParameters(bool& invert, - float& rescaleSlope, - float& rescaleIntercept, - float& windowWidth, - float& windowCenter, - const DicomMap& dicom) - { - DicomImageInformation info(dicom); - - invert = (info.GetPhotometricInterpretation() == PhotometricInterpretation_Monochrome1); - - rescaleSlope = 1.0f; - rescaleIntercept = 0.0f; - - if (dicom.HasTag(Orthanc::DICOM_TAG_RESCALE_SLOPE) && - dicom.HasTag(Orthanc::DICOM_TAG_RESCALE_INTERCEPT)) - { - dicom.ParseFloat(rescaleSlope, Orthanc::DICOM_TAG_RESCALE_SLOPE); - dicom.ParseFloat(rescaleIntercept, Orthanc::DICOM_TAG_RESCALE_INTERCEPT); - } - - windowWidth = static_cast(1 << info.GetBitsStored()) * rescaleSlope; - windowCenter = windowWidth / 2.0f + rescaleIntercept; - - if (dicom.HasTag(Orthanc::DICOM_TAG_WINDOW_CENTER) && - dicom.HasTag(Orthanc::DICOM_TAG_WINDOW_WIDTH)) - { - dicom.ParseFirstFloat(windowCenter, Orthanc::DICOM_TAG_WINDOW_CENTER); - dicom.ParseFirstFloat(windowWidth, Orthanc::DICOM_TAG_WINDOW_WIDTH); - } - } - - static void GetUserArguments(float& windowWidth /* inout */, - float& windowCenter /* inout */, - unsigned int& argWidth, - unsigned int& argHeight, - bool& smooth, - RestApiGetCall& call) - { - static const char* ARG_WINDOW_CENTER = "window-center"; - static const char* ARG_WINDOW_WIDTH = "window-width"; - static const char* ARG_WIDTH = "width"; - static const char* ARG_HEIGHT = "height"; - static const char* ARG_SMOOTH = "smooth"; - - if (call.HasArgument(ARG_WINDOW_WIDTH)) - { - try - { - windowWidth = boost::lexical_cast(call.GetArgument(ARG_WINDOW_WIDTH, "")); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Bad value for argument: " + std::string(ARG_WINDOW_WIDTH)); - } - } - - if (call.HasArgument(ARG_WINDOW_CENTER)) - { - try - { - windowCenter = boost::lexical_cast(call.GetArgument(ARG_WINDOW_CENTER, "")); - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Bad value for argument: " + std::string(ARG_WINDOW_CENTER)); - } - } - - argWidth = 0; - argHeight = 0; - - if (call.HasArgument(ARG_WIDTH)) - { - try - { - int tmp = boost::lexical_cast(call.GetArgument(ARG_WIDTH, "")); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Argument cannot be negative: " + std::string(ARG_WIDTH)); - } - else - { - argWidth = static_cast(tmp); - } - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Bad value for argument: " + std::string(ARG_WIDTH)); - } - } - - if (call.HasArgument(ARG_HEIGHT)) - { - try - { - int tmp = boost::lexical_cast(call.GetArgument(ARG_HEIGHT, "")); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Argument cannot be negative: " + std::string(ARG_HEIGHT)); - } - else - { - argHeight = static_cast(tmp); - } - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Bad value for argument: " + std::string(ARG_HEIGHT)); - } - } - - smooth = false; - - if (call.HasArgument(ARG_SMOOTH)) - { - std::string value = call.GetArgument(ARG_SMOOTH, ""); - if (value == "0" || - value == "false") - { - smooth = false; - } - else if (value == "1" || - value == "true") - { - smooth = true; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Argument must be Boolean: " + std::string(ARG_SMOOTH)); - } - } - } - - - public: - virtual void Handle(RestApiGetCall& call, - std::unique_ptr& decoded, - const DicomMap& dicom) ORTHANC_OVERRIDE - { - bool invert; - float rescaleSlope, rescaleIntercept, windowWidth, windowCenter; - GetDicomParameters(invert, rescaleSlope, rescaleIntercept, windowWidth, windowCenter, dicom); - - unsigned int argWidth, argHeight; - bool smooth; - GetUserArguments(windowWidth, windowCenter, argWidth, argHeight, smooth, call); - - unsigned int targetWidth = decoded->GetWidth(); - unsigned int targetHeight = decoded->GetHeight(); - - if (decoded->GetWidth() != 0 && - decoded->GetHeight() != 0) - { - float ratio = 1; - - if (argWidth != 0 && - argHeight != 0) - { - float ratioX = static_cast(argWidth) / static_cast(decoded->GetWidth()); - float ratioY = static_cast(argHeight) / static_cast(decoded->GetHeight()); - ratio = std::min(ratioX, ratioY); - } - else if (argWidth != 0) - { - ratio = static_cast(argWidth) / static_cast(decoded->GetWidth()); - } - else if (argHeight != 0) - { - ratio = static_cast(argHeight) / static_cast(decoded->GetHeight()); - } - - targetWidth = boost::math::iround(ratio * static_cast(decoded->GetWidth())); - targetHeight = boost::math::iround(ratio * static_cast(decoded->GetHeight())); - } - - if (decoded->GetFormat() == PixelFormat_RGB24) - { - if (targetWidth == decoded->GetWidth() && - targetHeight == decoded->GetHeight()) - { - DefaultHandler(call, decoded, ImageExtractionMode_Preview, false); - } - else - { - std::unique_ptr resized( - new Image(decoded->GetFormat(), targetWidth, targetHeight, false)); - - if (smooth && - (targetWidth < decoded->GetWidth() || - targetHeight < decoded->GetHeight())) - { - ImageProcessing::SmoothGaussian5x5(*decoded); - } - - ImageProcessing::Resize(*resized, *decoded); - DefaultHandler(call, resized, ImageExtractionMode_Preview, false); - } - } - else - { - // Grayscale image: (1) convert to Float32, (2) apply - // windowing to get a Grayscale8, (3) possibly resize - - Image converted(PixelFormat_Float32, decoded->GetWidth(), decoded->GetHeight(), false); - ImageProcessing::Convert(converted, *decoded); - - // Avoid divisions by zero - if (windowWidth <= 1.0f) - { - windowWidth = 1; - } - - if (std::abs(rescaleSlope) <= 0.1f) - { - rescaleSlope = 0.1f; - } - - const float scaling = 255.0f * rescaleSlope / windowWidth; - const float offset = (rescaleIntercept - windowCenter + windowWidth / 2.0f) / rescaleSlope; - - std::unique_ptr rescaled(new Image(PixelFormat_Grayscale8, decoded->GetWidth(), decoded->GetHeight(), false)); - ImageProcessing::ShiftScale(*rescaled, converted, offset, scaling, false); - - if (targetWidth == decoded->GetWidth() && - targetHeight == decoded->GetHeight()) - { - DefaultHandler(call, rescaled, ImageExtractionMode_UInt8, invert); - } - else - { - std::unique_ptr resized( - new Image(PixelFormat_Grayscale8, targetWidth, targetHeight, false)); - - if (smooth && - (targetWidth < decoded->GetWidth() || - targetHeight < decoded->GetHeight())) - { - ImageProcessing::SmoothGaussian5x5(*rescaled); - } - - ImageProcessing::Resize(*resized, *rescaled); - DefaultHandler(call, resized, ImageExtractionMode_UInt8, invert); - } - } - } - - virtual bool RequiresDicomTags() const ORTHANC_OVERRIDE - { - return true; - } - }; - } - - - template - static void GetImage(RestApiGetCall& call) - { - Semaphore::Locker locker(throttlingSemaphore_); - - GetImageHandler handler(mode); - IDecodedFrameHandler::Apply(call, handler); - } - - - static void GetRenderedFrame(RestApiGetCall& call) - { - Semaphore::Locker locker(throttlingSemaphore_); - - RenderedFrameHandler handler; - IDecodedFrameHandler::Apply(call, handler); - } - - - static void GetMatlabImage(RestApiGetCall& call) - { - Semaphore::Locker locker(throttlingSemaphore_); - - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string frameId = call.GetUriComponent("frame", "0"); - - unsigned int frame; - try - { - frame = boost::lexical_cast(frameId); - } - catch (boost::bad_lexical_cast&) - { - return; - } - - std::string publicId = call.GetUriComponent("id", ""); - std::unique_ptr decoded(context.DecodeDicomFrame(publicId, frame)); - - if (decoded.get() == NULL) - { - throw OrthancException(ErrorCode_NotImplemented, - "Cannot decode DICOM instance with ID: " + publicId); - } - else - { - std::string result; - decoded->ToMatlabString(result); - call.GetOutput().AnswerBuffer(result, MimeType_PlainText); - } - } - - - template - static void GetRawFrame(RestApiGetCall& call) - { - std::string frameId = call.GetUriComponent("frame", "0"); - - unsigned int frame; - try - { - frame = boost::lexical_cast(frameId); - } - catch (boost::bad_lexical_cast&) - { - return; - } - - std::string publicId = call.GetUriComponent("id", ""); - std::string raw; - MimeType mime; - - { - ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), publicId); - locker.GetDicom().GetRawFrame(raw, mime, frame); - } - - if (GzipCompression) - { - GzipCompressor gzip; - std::string compressed; - gzip.Compress(compressed, raw.empty() ? NULL : raw.c_str(), raw.size()); - call.GetOutput().AnswerBuffer(compressed, MimeType_Gzip); - } - else - { - call.GetOutput().AnswerBuffer(raw, mime); - } - } - - - static void GetResourceStatistics(RestApiGetCall& call) - { - static const uint64_t MEGA_BYTES = 1024 * 1024; - - std::string publicId = call.GetUriComponent("id", ""); - - ResourceType type; - uint64_t diskSize, uncompressedSize, dicomDiskSize, dicomUncompressedSize; - unsigned int countStudies, countSeries, countInstances; - OrthancRestApi::GetIndex(call).GetResourceStatistics( - type, diskSize, uncompressedSize, countStudies, countSeries, - countInstances, dicomDiskSize, dicomUncompressedSize, publicId); - - Json::Value result = Json::objectValue; - result["DiskSize"] = boost::lexical_cast(diskSize); - result["DiskSizeMB"] = static_cast(diskSize / MEGA_BYTES); - result["UncompressedSize"] = boost::lexical_cast(uncompressedSize); - result["UncompressedSizeMB"] = static_cast(uncompressedSize / MEGA_BYTES); - - result["DicomDiskSize"] = boost::lexical_cast(dicomDiskSize); - result["DicomDiskSizeMB"] = static_cast(dicomDiskSize / MEGA_BYTES); - result["DicomUncompressedSize"] = boost::lexical_cast(dicomUncompressedSize); - result["DicomUncompressedSizeMB"] = static_cast(dicomUncompressedSize / MEGA_BYTES); - - switch (type) - { - // Do NOT add "break" below this point! - case ResourceType_Patient: - result["CountStudies"] = countStudies; - - case ResourceType_Study: - result["CountSeries"] = countSeries; - - case ResourceType_Series: - result["CountInstances"] = countInstances; - - case ResourceType_Instance: - default: - break; - } - - call.GetOutput().AnswerJson(result); - } - - - - // Handling of metadata ----------------------------------------------------- - - static void CheckValidResourceType(RestApiCall& call) - { - std::string resourceType = call.GetUriComponent("resourceType", ""); - StringToResourceType(resourceType.c_str()); - } - - - static void ListMetadata(RestApiGetCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::map metadata; - - OrthancRestApi::GetIndex(call).GetAllMetadata(metadata, publicId); - - Json::Value result; - - if (call.HasArgument("expand")) - { - result = Json::objectValue; - - for (std::map::const_iterator - it = metadata.begin(); it != metadata.end(); ++it) - { - std::string key = EnumerationToString(it->first); - result[key] = it->second; - } - } - else - { - result = Json::arrayValue; - - for (std::map::const_iterator - it = metadata.begin(); it != metadata.end(); ++it) - { - result.append(EnumerationToString(it->first)); - } - } - - call.GetOutput().AnswerJson(result); - } - - - static void GetMetadata(RestApiGetCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - MetadataType metadata = StringToMetadata(name); - - std::string value; - if (OrthancRestApi::GetIndex(call).LookupMetadata(value, publicId, metadata)) - { - call.GetOutput().AnswerBuffer(value, MimeType_PlainText); - } - } - - - static void DeleteMetadata(RestApiDeleteCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - MetadataType metadata = StringToMetadata(name); - - if (IsUserMetadata(metadata)) // It is forbidden to modify internal metadata - { - OrthancRestApi::GetIndex(call).DeleteMetadata(publicId, metadata); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - else - { - call.GetOutput().SignalError(HttpStatus_403_Forbidden); - } - } - - - static void SetMetadata(RestApiPutCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - MetadataType metadata = StringToMetadata(name); - - std::string value; - call.BodyToString(value); - - if (IsUserMetadata(metadata)) // It is forbidden to modify internal metadata - { - // It is forbidden to modify internal metadata - OrthancRestApi::GetIndex(call).SetMetadata(publicId, metadata, value); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - else - { - call.GetOutput().SignalError(HttpStatus_403_Forbidden); - } - } - - - - - // Handling of attached files ----------------------------------------------- - - static void ListAttachments(RestApiGetCall& call) - { - std::string resourceType = call.GetUriComponent("resourceType", ""); - std::string publicId = call.GetUriComponent("id", ""); - std::list attachments; - OrthancRestApi::GetIndex(call).ListAvailableAttachments(attachments, publicId, StringToResourceType(resourceType.c_str())); - - Json::Value result = Json::arrayValue; - - for (std::list::const_iterator - it = attachments.begin(); it != attachments.end(); ++it) - { - result.append(EnumerationToString(*it)); - } - - call.GetOutput().AnswerJson(result); - } - - - static bool GetAttachmentInfo(FileInfo& info, RestApiCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - FileContentType contentType = StringToContentType(name); - - return OrthancRestApi::GetIndex(call).LookupAttachment(info, publicId, contentType); - } - - - static void GetAttachmentOperations(RestApiGetCall& call) - { - FileInfo info; - if (GetAttachmentInfo(info, call)) - { - Json::Value operations = Json::arrayValue; - - operations.append("compress"); - operations.append("compressed-data"); - - if (info.GetCompressedMD5() != "") - { - operations.append("compressed-md5"); - } - - operations.append("compressed-size"); - operations.append("data"); - operations.append("is-compressed"); - - if (info.GetUncompressedMD5() != "") - { - operations.append("md5"); - } - - operations.append("size"); - operations.append("uncompress"); - - if (info.GetCompressedMD5() != "" && - info.GetUncompressedMD5() != "") - { - operations.append("verify-md5"); - } - - call.GetOutput().AnswerJson(operations); - } - } - - - template - static void GetAttachmentData(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - FileContentType type = StringToContentType(call.GetUriComponent("name", "")); - - if (uncompress) - { - context.AnswerAttachment(call.GetOutput(), publicId, type); - } - else - { - // Return the raw data (possibly compressed), as stored on the filesystem - std::string content; - context.ReadAttachment(content, publicId, type, false); - call.GetOutput().AnswerBuffer(content, MimeType_Binary); - } - } - - - static void GetAttachmentSize(RestApiGetCall& call) - { - FileInfo info; - if (GetAttachmentInfo(info, call)) - { - call.GetOutput().AnswerBuffer(boost::lexical_cast(info.GetUncompressedSize()), MimeType_PlainText); - } - } - - - static void GetAttachmentCompressedSize(RestApiGetCall& call) - { - FileInfo info; - if (GetAttachmentInfo(info, call)) - { - call.GetOutput().AnswerBuffer(boost::lexical_cast(info.GetCompressedSize()), MimeType_PlainText); - } - } - - - static void GetAttachmentMD5(RestApiGetCall& call) - { - FileInfo info; - if (GetAttachmentInfo(info, call) && - info.GetUncompressedMD5() != "") - { - call.GetOutput().AnswerBuffer(boost::lexical_cast(info.GetUncompressedMD5()), MimeType_PlainText); - } - } - - - static void GetAttachmentCompressedMD5(RestApiGetCall& call) - { - FileInfo info; - if (GetAttachmentInfo(info, call) && - info.GetCompressedMD5() != "") - { - call.GetOutput().AnswerBuffer(boost::lexical_cast(info.GetCompressedMD5()), MimeType_PlainText); - } - } - - - static void VerifyAttachment(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - - FileInfo info; - if (!GetAttachmentInfo(info, call) || - info.GetCompressedMD5() == "" || - info.GetUncompressedMD5() == "") - { - // Inexistent resource, or no MD5 available - return; - } - - bool ok = false; - - // First check whether the compressed data is correctly stored in the disk - std::string data; - context.ReadAttachment(data, publicId, StringToContentType(name), false); - - std::string actualMD5; - Toolbox::ComputeMD5(actualMD5, data); - - if (actualMD5 == info.GetCompressedMD5()) - { - // The compressed data is OK. If a compression algorithm was - // applied to it, now check the MD5 of the uncompressed data. - if (info.GetCompressionType() == CompressionType_None) - { - ok = true; - } - else - { - context.ReadAttachment(data, publicId, StringToContentType(name), true); - Toolbox::ComputeMD5(actualMD5, data); - ok = (actualMD5 == info.GetUncompressedMD5()); - } - } - - if (ok) - { - LOG(INFO) << "The attachment " << name << " of resource " << publicId << " has the right MD5"; - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - else - { - LOG(INFO) << "The attachment " << name << " of resource " << publicId << " has bad MD5!"; - } - } - - - static void UploadAttachment(RestApiPutCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - - FileContentType contentType = StringToContentType(name); - if (IsUserContentType(contentType) && // It is forbidden to modify internal attachments - context.AddAttachment(publicId, StringToContentType(name), call.GetBodyData(), call.GetBodySize())) - { - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - else - { - call.GetOutput().SignalError(HttpStatus_403_Forbidden); - } - } - - - static void DeleteAttachment(RestApiDeleteCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - FileContentType contentType = StringToContentType(name); - - bool allowed; - if (IsUserContentType(contentType)) - { - allowed = true; - } - else - { - OrthancConfiguration::ReaderLock lock; - - if (lock.GetConfiguration().GetBooleanParameter("StoreDicom", true) && - contentType == FileContentType_DicomAsJson) - { - allowed = true; - } - else - { - // It is forbidden to delete internal attachments, except for - // the "DICOM as JSON" summary as of Orthanc 1.2.0 (this summary - // would be automatically reconstructed on the next GET call) - allowed = false; - } - } - - if (allowed) - { - OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType); - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - else - { - call.GetOutput().SignalError(HttpStatus_403_Forbidden); - } - } - - - template - static void ChangeAttachmentCompression(RestApiPostCall& call) - { - CheckValidResourceType(call); - - std::string publicId = call.GetUriComponent("id", ""); - std::string name = call.GetUriComponent("name", ""); - FileContentType contentType = StringToContentType(name); - - OrthancRestApi::GetContext(call).ChangeAttachmentCompression(publicId, contentType, compression); - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - - - static void IsAttachmentCompressed(RestApiGetCall& call) - { - FileInfo info; - if (GetAttachmentInfo(info, call)) - { - std::string answer = (info.GetCompressionType() == CompressionType_None) ? "0" : "1"; - call.GetOutput().AnswerBuffer(answer, MimeType_PlainText); - } - } - - - // Raw access to the DICOM tags of an instance ------------------------------ - - static void GetRawContent(RestApiGetCall& call) - { - std::string id = call.GetUriComponent("id", ""); - - ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), id); - - locker.GetDicom().SendPathValue(call.GetOutput(), call.GetTrailingUri()); - } - - - - static bool ExtractSharedTags(Json::Value& shared, - ServerContext& context, - const std::string& publicId) - { - // Retrieve all the instances of this patient/study/series - typedef std::list Instances; - Instances instances; - context.GetIndex().GetChildInstances(instances, publicId); // (*) - - // Loop over the instances - bool isFirst = true; - shared = Json::objectValue; - - for (Instances::const_iterator it = instances.begin(); - it != instances.end(); ++it) - { - // Get the tags of the current instance, in the simplified format - Json::Value tags; - - try - { - context.ReadDicomAsJson(tags, *it); - } - catch (OrthancException&) - { - // Race condition: This instance has been removed since - // (*). Ignore this instance. - continue; - } - - if (tags.type() != Json::objectValue) - { - return false; // Error - } - - // Only keep the tags that are mapped to a string - Json::Value::Members members = tags.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& tag = tags[members[i]]; - if (tag.type() != Json::objectValue || - tag["Type"].type() != Json::stringValue || - tag["Type"].asString() != "String") - { - tags.removeMember(members[i]); - } - } - - if (isFirst) - { - // This is the first instance, keep its tags as such - shared = tags; - isFirst = false; - } - else - { - // Loop over all the members of the shared tags extracted so - // far. If the value of one of these tags does not match its - // value in the current instance, remove it. - members = shared.getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - if (!tags.isMember(members[i]) || - tags[members[i]]["Value"].asString() != shared[members[i]]["Value"].asString()) - { - shared.removeMember(members[i]); - } - } - } - } - - return true; - } - - - static void GetSharedTags(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - std::string publicId = call.GetUriComponent("id", ""); - - Json::Value sharedTags; - if (ExtractSharedTags(sharedTags, context, publicId)) - { - // Success: Send the value of the shared tags - AnswerDicomAsJson(call, sharedTags); - } - } - - - static void GetModuleInternal(RestApiGetCall& call, - ResourceType resourceType, - DicomModule module) - { - if (!((resourceType == ResourceType_Patient && module == DicomModule_Patient) || - (resourceType == ResourceType_Study && module == DicomModule_Patient) || - (resourceType == ResourceType_Study && module == DicomModule_Study) || - (resourceType == ResourceType_Series && module == DicomModule_Series) || - (resourceType == ResourceType_Instance && module == DicomModule_Instance) || - (resourceType == ResourceType_Instance && module == DicomModule_Image))) - { - throw OrthancException(ErrorCode_NotImplemented); - } - - ServerContext& context = OrthancRestApi::GetContext(call); - std::string publicId = call.GetUriComponent("id", ""); - - std::set ignoreTagLength; - ParseSetOfTags(ignoreTagLength, call, "ignore-length"); - - typedef std::set ModuleTags; - ModuleTags moduleTags; - DicomTag::AddTagsForModule(moduleTags, module); - - Json::Value tags; - - if (resourceType != ResourceType_Instance) - { - // Retrieve all the instances of this patient/study/series - typedef std::list Instances; - Instances instances; - context.GetIndex().GetChildInstances(instances, publicId); - - if (instances.empty()) - { - return; // Error: No instance (should never happen) - } - - // Select one child instance - publicId = instances.front(); - } - - context.ReadDicomAsJson(tags, publicId, ignoreTagLength); - - // Filter the tags of the instance according to the module - Json::Value result = Json::objectValue; - for (ModuleTags::const_iterator tag = moduleTags.begin(); tag != moduleTags.end(); ++tag) - { - std::string s = tag->Format(); - if (tags.isMember(s)) - { - result[s] = tags[s]; - } - } - - AnswerDicomAsJson(call, result); - } - - - - template - static void GetModule(RestApiGetCall& call) - { - GetModuleInternal(call, resourceType, module); - } - - - namespace - { - typedef std::list< std::pair > LookupResults; - } - - - static void AccumulateLookupResults(LookupResults& result, - ServerIndex& index, - const DicomTag& tag, - const std::string& value, - ResourceType level) - { - std::vector tmp; - index.LookupIdentifierExact(tmp, level, tag, value); - - for (size_t i = 0; i < tmp.size(); i++) - { - result.push_back(std::make_pair(level, tmp[i])); - } - } - - - static void Lookup(RestApiPostCall& call) - { - std::string tag; - call.BodyToString(tag); - - LookupResults resources; - ServerIndex& index = OrthancRestApi::GetIndex(call); - AccumulateLookupResults(resources, index, DICOM_TAG_PATIENT_ID, tag, ResourceType_Patient); - AccumulateLookupResults(resources, index, DICOM_TAG_STUDY_INSTANCE_UID, tag, ResourceType_Study); - AccumulateLookupResults(resources, index, DICOM_TAG_SERIES_INSTANCE_UID, tag, ResourceType_Series); - AccumulateLookupResults(resources, index, DICOM_TAG_SOP_INSTANCE_UID, tag, ResourceType_Instance); - - Json::Value result = Json::arrayValue; - for (LookupResults::const_iterator - it = resources.begin(); it != resources.end(); ++it) - { - ResourceType type = it->first; - const std::string& id = it->second; - - Json::Value item = Json::objectValue; - item["Type"] = EnumerationToString(type); - item["ID"] = id; - item["Path"] = GetBasePath(type, id); - - result.append(item); - } - - call.GetOutput().AnswerJson(result); - } - - - namespace - { - class FindVisitor : public ServerContext::ILookupVisitor - { - private: - bool isComplete_; - std::list resources_; - - public: - FindVisitor() : - isComplete_(false) - { - } - - virtual bool IsDicomAsJsonNeeded() const - { - return false; // (*) - } - - virtual void MarkAsComplete() - { - isComplete_ = true; // Unused information as of Orthanc 1.5.0 - } - - virtual void Visit(const std::string& publicId, - const std::string& instanceId /* unused */, - const DicomMap& mainDicomTags /* unused */, - const Json::Value* dicomAsJson /* unused (*) */) - { - resources_.push_back(publicId); - } - - void Answer(RestApiOutput& output, - ServerIndex& index, - ResourceType level, - bool expand) const - { - AnswerListOfResources(output, index, resources_, level, expand); - } - }; - } - - - static void Find(RestApiPostCall& call) - { - static const char* const KEY_CASE_SENSITIVE = "CaseSensitive"; - static const char* const KEY_EXPAND = "Expand"; - static const char* const KEY_LEVEL = "Level"; - static const char* const KEY_LIMIT = "Limit"; - static const char* const KEY_QUERY = "Query"; - static const char* const KEY_SINCE = "Since"; - - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value request; - if (!call.ParseJsonRequest(request) || - request.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadRequest, - "The body must contain a JSON object"); - } - else if (!request.isMember(KEY_LEVEL) || - request[KEY_LEVEL].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_LEVEL) + "\" is missing, or should be a string"); - } - else if (!request.isMember(KEY_QUERY) && - request[KEY_QUERY].type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_QUERY) + "\" is missing, or should be a JSON object"); - } - else if (request.isMember(KEY_CASE_SENSITIVE) && - request[KEY_CASE_SENSITIVE].type() != Json::booleanValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_CASE_SENSITIVE) + "\" should be a Boolean"); - } - else if (request.isMember(KEY_LIMIT) && - request[KEY_LIMIT].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_LIMIT) + "\" should be an integer"); - } - else if (request.isMember(KEY_SINCE) && - request[KEY_SINCE].type() != Json::intValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Field \"" + std::string(KEY_SINCE) + "\" should be an integer"); - } - else - { - bool expand = false; - if (request.isMember(KEY_EXPAND)) - { - expand = request[KEY_EXPAND].asBool(); - } - - bool caseSensitive = false; - if (request.isMember(KEY_CASE_SENSITIVE)) - { - caseSensitive = request[KEY_CASE_SENSITIVE].asBool(); - } - - size_t limit = 0; - if (request.isMember(KEY_LIMIT)) - { - int tmp = request[KEY_LIMIT].asInt(); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_LIMIT) + "\" should be a positive integer"); - } - - limit = static_cast(tmp); - } - - size_t since = 0; - if (request.isMember(KEY_SINCE)) - { - int tmp = request[KEY_SINCE].asInt(); - if (tmp < 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Field \"" + std::string(KEY_SINCE) + "\" should be a positive integer"); - } - - since = static_cast(tmp); - } - - ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString()); - - DatabaseLookup query; - - Json::Value::Members members = request[KEY_QUERY].getMemberNames(); - for (size_t i = 0; i < members.size(); i++) - { - if (request[KEY_QUERY][members[i]].type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadRequest, - "Tag \"" + members[i] + "\" should be associated with a string"); - } - - const std::string value = request[KEY_QUERY][members[i]].asString(); - - if (!value.empty()) - { - // An empty string corresponds to an universal constraint, - // so we ignore it. This mimics the behavior of class - // "OrthancFindRequestHandler" - query.AddRestConstraint(FromDcmtkBridge::ParseTag(members[i]), - value, caseSensitive, true); - } - } - - FindVisitor visitor; - context.Apply(visitor, query, level, since, limit); - visitor.Answer(call.GetOutput(), context.GetIndex(), level, expand); - } - } - - - template - static void GetChildResources(RestApiGetCall& call) - { - ServerIndex& index = OrthancRestApi::GetIndex(call); - - std::list a, b, c; - a.push_back(call.GetUriComponent("id", "")); - - ResourceType type = start; - while (type != end) - { - b.clear(); - - for (std::list::const_iterator - it = a.begin(); it != a.end(); ++it) - { - index.GetChildren(c, *it); - b.splice(b.begin(), c); - } - - type = GetChildResourceType(type); - - a.clear(); - a.splice(a.begin(), b); - } - - Json::Value result = Json::arrayValue; - - for (std::list::const_iterator - it = a.begin(); it != a.end(); ++it) - { - Json::Value item; - - if (OrthancRestApi::GetIndex(call).LookupResource(item, *it, end)) - { - result.append(item); - } - } - - call.GetOutput().AnswerJson(result); - } - - - static void GetChildInstancesTags(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - std::string publicId = call.GetUriComponent("id", ""); - DicomToJsonFormat format = GetDicomFormat(call); - - std::set ignoreTagLength; - ParseSetOfTags(ignoreTagLength, call, "ignore-length"); - - // Retrieve all the instances of this patient/study/series - typedef std::list Instances; - Instances instances; - - context.GetIndex().GetChildInstances(instances, publicId); // (*) - - Json::Value result = Json::objectValue; - - for (Instances::const_iterator it = instances.begin(); - it != instances.end(); ++it) - { - Json::Value full; - context.ReadDicomAsJson(full, *it, ignoreTagLength); - - if (format != DicomToJsonFormat_Full) - { - Json::Value simplified; - ServerToolbox::SimplifyTags(simplified, full, format); - result[*it] = simplified; - } - else - { - result[*it] = full; - } - } - - call.GetOutput().AnswerJson(result); - } - - - - template - static void GetParentResource(RestApiGetCall& call) - { - assert(start > end); - - ServerIndex& index = OrthancRestApi::GetIndex(call); - - std::string current = call.GetUriComponent("id", ""); - ResourceType currentType = start; - while (currentType > end) - { - std::string parent; - if (!index.LookupParent(parent, current)) - { - // Error that could happen if the resource gets deleted by - // another concurrent call - return; - } - - current = parent; - currentType = GetParentResourceType(currentType); - } - - assert(currentType == end); - - Json::Value result; - if (index.LookupResource(result, current, end)) - { - call.GetOutput().AnswerJson(result); - } - } - - - static void ExtractPdf(RestApiGetCall& call) - { - const std::string id = call.GetUriComponent("id", ""); - - std::string pdf; - ServerContext::DicomCacheLocker locker(OrthancRestApi::GetContext(call), id); - - if (locker.GetDicom().ExtractPdf(pdf)) - { - call.GetOutput().AnswerBuffer(pdf, MimeType_Pdf); - return; - } - } - - - static void OrderSlices(RestApiGetCall& call) - { - const std::string id = call.GetUriComponent("id", ""); - - ServerIndex& index = OrthancRestApi::GetIndex(call); - SliceOrdering ordering(index, id); - - Json::Value result; - ordering.Format(result); - call.GetOutput().AnswerJson(result); - } - - - static void GetInstanceHeader(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::string publicId = call.GetUriComponent("id", ""); - - std::string dicomContent; - context.ReadDicom(dicomContent, publicId); - - // TODO Consider using "DicomMap::ParseDicomMetaInformation()" to - // speed up things here - - ParsedDicomFile dicom(dicomContent); - - Json::Value header; - dicom.HeaderToJson(header, DicomToJsonFormat_Full); - - AnswerDicomAsJson(call, header); - } - - - static void InvalidateTags(RestApiPostCall& call) - { - ServerIndex& index = OrthancRestApi::GetIndex(call); - - // Loop over the instances, grouping them by parent studies so as - // to avoid large memory consumption - std::list studies; - index.GetAllUuids(studies, ResourceType_Study); - - for (std::list::const_iterator - study = studies.begin(); study != studies.end(); ++study) - { - std::list instances; - index.GetChildInstances(instances, *study); - - for (std::list::const_iterator - instance = instances.begin(); instance != instances.end(); ++instance) - { - index.DeleteAttachment(*instance, FileContentType_DicomAsJson); - } - } - - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - template - static void ReconstructResource(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - ServerToolbox::ReconstructResource(context, call.GetUriComponent("id", "")); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - static void ReconstructAllResources(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - std::list studies; - context.GetIndex().GetAllUuids(studies, ResourceType_Study); - - for (std::list::const_iterator - study = studies.begin(); study != studies.end(); ++study) - { - ServerToolbox::ReconstructResource(context, *study); - } - - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - void OrthancRestApi::RegisterResources() - { - Register("/instances", ListResources); - Register("/patients", ListResources); - Register("/series", ListResources); - Register("/studies", ListResources); - - Register("/instances/{id}", DeleteSingleResource); - Register("/instances/{id}", GetSingleResource); - Register("/patients/{id}", DeleteSingleResource); - Register("/patients/{id}", GetSingleResource); - Register("/series/{id}", DeleteSingleResource); - Register("/series/{id}", GetSingleResource); - Register("/studies/{id}", DeleteSingleResource); - Register("/studies/{id}", GetSingleResource); - - Register("/instances/{id}/statistics", GetResourceStatistics); - Register("/patients/{id}/statistics", GetResourceStatistics); - Register("/studies/{id}/statistics", GetResourceStatistics); - Register("/series/{id}/statistics", GetResourceStatistics); - - Register("/patients/{id}/shared-tags", GetSharedTags); - Register("/series/{id}/shared-tags", GetSharedTags); - Register("/studies/{id}/shared-tags", GetSharedTags); - - Register("/instances/{id}/module", GetModule); - Register("/patients/{id}/module", GetModule); - Register("/series/{id}/module", GetModule); - Register("/studies/{id}/module", GetModule); - Register("/studies/{id}/module-patient", GetModule); - - Register("/instances/{id}/file", GetInstanceFile); - Register("/instances/{id}/export", ExportInstanceFile); - Register("/instances/{id}/tags", GetInstanceTagsBis); - Register("/instances/{id}/simplified-tags", GetInstanceTags); - Register("/instances/{id}/frames", ListFrames); - - Register("/instances/{id}/frames/{frame}/preview", GetImage); - Register("/instances/{id}/frames/{frame}/rendered", GetRenderedFrame); - Register("/instances/{id}/frames/{frame}/image-uint8", GetImage); - Register("/instances/{id}/frames/{frame}/image-uint16", GetImage); - Register("/instances/{id}/frames/{frame}/image-int16", GetImage); - Register("/instances/{id}/frames/{frame}/matlab", GetMatlabImage); - Register("/instances/{id}/frames/{frame}/raw", GetRawFrame); - Register("/instances/{id}/frames/{frame}/raw.gz", GetRawFrame); - Register("/instances/{id}/pdf", ExtractPdf); - Register("/instances/{id}/preview", GetImage); - Register("/instances/{id}/rendered", GetRenderedFrame); - Register("/instances/{id}/image-uint8", GetImage); - Register("/instances/{id}/image-uint16", GetImage); - Register("/instances/{id}/image-int16", GetImage); - Register("/instances/{id}/matlab", GetMatlabImage); - Register("/instances/{id}/header", GetInstanceHeader); - - Register("/patients/{id}/protected", IsProtectedPatient); - Register("/patients/{id}/protected", SetPatientProtection); - - Register("/{resourceType}/{id}/metadata", ListMetadata); - Register("/{resourceType}/{id}/metadata/{name}", DeleteMetadata); - Register("/{resourceType}/{id}/metadata/{name}", GetMetadata); - Register("/{resourceType}/{id}/metadata/{name}", SetMetadata); - - Register("/{resourceType}/{id}/attachments", ListAttachments); - Register("/{resourceType}/{id}/attachments/{name}", DeleteAttachment); - Register("/{resourceType}/{id}/attachments/{name}", GetAttachmentOperations); - Register("/{resourceType}/{id}/attachments/{name}", UploadAttachment); - Register("/{resourceType}/{id}/attachments/{name}/compress", ChangeAttachmentCompression); - Register("/{resourceType}/{id}/attachments/{name}/compressed-data", GetAttachmentData<0>); - Register("/{resourceType}/{id}/attachments/{name}/compressed-md5", GetAttachmentCompressedMD5); - Register("/{resourceType}/{id}/attachments/{name}/compressed-size", GetAttachmentCompressedSize); - Register("/{resourceType}/{id}/attachments/{name}/data", GetAttachmentData<1>); - Register("/{resourceType}/{id}/attachments/{name}/is-compressed", IsAttachmentCompressed); - Register("/{resourceType}/{id}/attachments/{name}/md5", GetAttachmentMD5); - Register("/{resourceType}/{id}/attachments/{name}/size", GetAttachmentSize); - Register("/{resourceType}/{id}/attachments/{name}/uncompress", ChangeAttachmentCompression); - Register("/{resourceType}/{id}/attachments/{name}/verify-md5", VerifyAttachment); - - Register("/tools/invalidate-tags", InvalidateTags); - Register("/tools/lookup", Lookup); - Register("/tools/find", Find); - - Register("/patients/{id}/studies", GetChildResources); - Register("/patients/{id}/series", GetChildResources); - Register("/patients/{id}/instances", GetChildResources); - Register("/studies/{id}/series", GetChildResources); - Register("/studies/{id}/instances", GetChildResources); - Register("/series/{id}/instances", GetChildResources); - - Register("/studies/{id}/patient", GetParentResource); - Register("/series/{id}/patient", GetParentResource); - Register("/series/{id}/study", GetParentResource); - Register("/instances/{id}/patient", GetParentResource); - Register("/instances/{id}/study", GetParentResource); - Register("/instances/{id}/series", GetParentResource); - - Register("/patients/{id}/instances-tags", GetChildInstancesTags); - Register("/studies/{id}/instances-tags", GetChildInstancesTags); - Register("/series/{id}/instances-tags", GetChildInstancesTags); - - Register("/instances/{id}/content/*", GetRawContent); - - Register("/series/{id}/ordered-slices", OrderSlices); - - Register("/patients/{id}/reconstruct", ReconstructResource); - Register("/studies/{id}/reconstruct", ReconstructResource); - Register("/series/{id}/reconstruct", ReconstructResource); - Register("/instances/{id}/reconstruct", ReconstructResource); - Register("/tools/reconstruct", ReconstructAllResources); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,584 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancRestApi.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/MetricsRegistry.h" -#include "../../Plugins/Engine/OrthancPlugins.h" -#include "../../Plugins/Engine/PluginsManager.h" -#include "../OrthancConfiguration.h" -#include "../ServerContext.h" - - -static const char* LOG_LEVEL_DEFAULT = "default"; -static const char* LOG_LEVEL_VERBOSE = "verbose"; -static const char* LOG_LEVEL_TRACE = "trace"; - - -namespace Orthanc -{ - // System information ------------------------------------------------------- - - static void ServeRoot(RestApiGetCall& call) - { - call.GetOutput().Redirect("app/explorer.html"); - } - - static void GetSystemInformation(RestApiGetCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - Json::Value result = Json::objectValue; - - result["ApiVersion"] = ORTHANC_API_VERSION; - result["Version"] = ORTHANC_VERSION; - result["DatabaseVersion"] = OrthancRestApi::GetIndex(call).GetDatabaseVersion(); - result["IsHttpServerSecure"] = context.IsHttpServerSecure(); // New in Orthanc 1.5.8 - - { - OrthancConfiguration::ReaderLock lock; - result["DicomAet"] = lock.GetConfiguration().GetStringParameter("DicomAet", "ORTHANC"); - result["DicomPort"] = lock.GetConfiguration().GetUnsignedIntegerParameter("DicomPort", 4242); - result["HttpPort"] = lock.GetConfiguration().GetUnsignedIntegerParameter("HttpPort", 8042); - result["Name"] = lock.GetConfiguration().GetStringParameter("Name", ""); - } - - result["StorageAreaPlugin"] = Json::nullValue; - result["DatabaseBackendPlugin"] = Json::nullValue; - -#if ORTHANC_ENABLE_PLUGINS == 1 - result["PluginsEnabled"] = true; - const OrthancPlugins& plugins = context.GetPlugins(); - - if (plugins.HasStorageArea()) - { - std::string p = plugins.GetStorageAreaLibrary().GetPath(); - result["StorageAreaPlugin"] = boost::filesystem::canonical(p).string(); - } - - if (plugins.HasDatabaseBackend()) - { - std::string p = plugins.GetDatabaseBackendLibrary().GetPath(); - result["DatabaseBackendPlugin"] = boost::filesystem::canonical(p).string(); - } -#else - result["PluginsEnabled"] = false; -#endif - - call.GetOutput().AnswerJson(result); - } - - static void GetStatistics(RestApiGetCall& call) - { - static const uint64_t MEGA_BYTES = 1024 * 1024; - - uint64_t diskSize, uncompressedSize, countPatients, countStudies, countSeries, countInstances; - OrthancRestApi::GetIndex(call).GetGlobalStatistics(diskSize, uncompressedSize, countPatients, - countStudies, countSeries, countInstances); - - Json::Value result = Json::objectValue; - result["TotalDiskSize"] = boost::lexical_cast(diskSize); - result["TotalUncompressedSize"] = boost::lexical_cast(uncompressedSize); - result["TotalDiskSizeMB"] = static_cast(diskSize / MEGA_BYTES); - result["TotalUncompressedSizeMB"] = static_cast(uncompressedSize / MEGA_BYTES); - result["CountPatients"] = static_cast(countPatients); - result["CountStudies"] = static_cast(countStudies); - result["CountSeries"] = static_cast(countSeries); - result["CountInstances"] = static_cast(countInstances); - - call.GetOutput().AnswerJson(result); - } - - static void GenerateUid(RestApiGetCall& call) - { - std::string level = call.GetArgument("level", ""); - if (level == "patient") - { - call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient), MimeType_PlainText); - } - else if (level == "study") - { - call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study), MimeType_PlainText); - } - else if (level == "series") - { - call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series), MimeType_PlainText); - } - else if (level == "instance") - { - call.GetOutput().AnswerBuffer(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance), MimeType_PlainText); - } - } - - static void ExecuteScript(RestApiPostCall& call) - { - ServerContext& context = OrthancRestApi::GetContext(call); - - if (!context.IsExecuteLuaEnabled()) - { - LOG(ERROR) << "The URI /tools/execute-script is disallowed for security, " - << "check your configuration file"; - call.GetOutput().SignalError(HttpStatus_403_Forbidden); - return; - } - - std::string result; - std::string command; - call.BodyToString(command); - - { - LuaScripting::Lock lock(context.GetLuaScripting()); - lock.GetLua().Execute(result, command); - } - - call.GetOutput().AnswerBuffer(result, MimeType_PlainText); - } - - template - static void GetNowIsoString(RestApiGetCall& call) - { - call.GetOutput().AnswerBuffer(SystemToolbox::GetNowIsoString(UTC), MimeType_PlainText); - } - - - static void GetDicomConformanceStatement(RestApiGetCall& call) - { - std::string statement; - GetFileResource(statement, EmbeddedResources::DICOM_CONFORMANCE_STATEMENT); - call.GetOutput().AnswerBuffer(statement, MimeType_PlainText); - } - - - static void GetDefaultEncoding(RestApiGetCall& call) - { - Encoding encoding = GetDefaultDicomEncoding(); - call.GetOutput().AnswerBuffer(EnumerationToString(encoding), MimeType_PlainText); - } - - - static void SetDefaultEncoding(RestApiPutCall& call) - { - std::string body; - call.BodyToString(body); - - Encoding encoding = StringToEncoding(body.c_str()); - - { - OrthancConfiguration::WriterLock lock; - lock.GetConfiguration().SetDefaultEncoding(encoding); - } - - call.GetOutput().AnswerBuffer(EnumerationToString(encoding), MimeType_PlainText); - } - - - - // Plugins information ------------------------------------------------------ - - static void ListPlugins(RestApiGetCall& call) - { - Json::Value v = Json::arrayValue; - - v.append("explorer.js"); - - if (OrthancRestApi::GetContext(call).HasPlugins()) - { -#if ORTHANC_ENABLE_PLUGINS == 1 - std::list plugins; - OrthancRestApi::GetContext(call).GetPlugins().GetManager().ListPlugins(plugins); - - for (std::list::const_iterator - it = plugins.begin(); it != plugins.end(); ++it) - { - v.append(*it); - } -#endif - } - - call.GetOutput().AnswerJson(v); - } - - - static void GetPlugin(RestApiGetCall& call) - { - if (!OrthancRestApi::GetContext(call).HasPlugins()) - { - return; - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - const PluginsManager& manager = OrthancRestApi::GetContext(call).GetPlugins().GetManager(); - std::string id = call.GetUriComponent("id", ""); - - if (manager.HasPlugin(id)) - { - Json::Value v = Json::objectValue; - v["ID"] = id; - v["Version"] = manager.GetPluginVersion(id); - - const OrthancPlugins& plugins = OrthancRestApi::GetContext(call).GetPlugins(); - const char *c = plugins.GetProperty(id.c_str(), _OrthancPluginProperty_RootUri); - if (c != NULL) - { - std::string root = c; - if (!root.empty()) - { - // Turn the root URI into a URI relative to "/app/explorer.js" - if (root[0] == '/') - { - root = ".." + root; - } - - v["RootUri"] = root; - } - } - - c = plugins.GetProperty(id.c_str(), _OrthancPluginProperty_Description); - if (c != NULL) - { - v["Description"] = c; - } - - c = plugins.GetProperty(id.c_str(), _OrthancPluginProperty_OrthancExplorer); - v["ExtendsOrthancExplorer"] = (c != NULL); - - call.GetOutput().AnswerJson(v); - } -#endif - } - - - static void GetOrthancExplorerPlugins(RestApiGetCall& call) - { - std::string s = "// Extensions to Orthanc Explorer by the registered plugins\n\n"; - - if (OrthancRestApi::GetContext(call).HasPlugins()) - { -#if ORTHANC_ENABLE_PLUGINS == 1 - const OrthancPlugins& plugins = OrthancRestApi::GetContext(call).GetPlugins(); - const PluginsManager& manager = plugins.GetManager(); - - std::list lst; - manager.ListPlugins(lst); - - for (std::list::const_iterator - it = lst.begin(); it != lst.end(); ++it) - { - const char* tmp = plugins.GetProperty(it->c_str(), _OrthancPluginProperty_OrthancExplorer); - if (tmp != NULL) - { - s += "/**\n * From plugin: " + *it + " (version " + manager.GetPluginVersion(*it) + ")\n **/\n\n"; - s += std::string(tmp) + "\n\n"; - } - } -#endif - } - - call.GetOutput().AnswerBuffer(s, MimeType_JavaScript); - } - - - - - // Jobs information ------------------------------------------------------ - - static void ListJobs(RestApiGetCall& call) - { - bool expand = call.HasArgument("expand"); - - Json::Value v = Json::arrayValue; - - std::set jobs; - OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().ListJobs(jobs); - - for (std::set::const_iterator it = jobs.begin(); - it != jobs.end(); ++it) - { - if (expand) - { - JobInfo info; - if (OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().GetJobInfo(info, *it)) - { - Json::Value tmp; - info.Format(tmp); - v.append(tmp); - } - } - else - { - v.append(*it); - } - } - - call.GetOutput().AnswerJson(v); - } - - static void GetJobInfo(RestApiGetCall& call) - { - std::string id = call.GetUriComponent("id", ""); - - JobInfo info; - if (OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().GetJobInfo(info, id)) - { - Json::Value json; - info.Format(json); - call.GetOutput().AnswerJson(json); - } - } - - - static void GetJobOutput(RestApiGetCall& call) - { - std::string job = call.GetUriComponent("id", ""); - std::string key = call.GetUriComponent("key", ""); - - std::string value; - MimeType mime; - - if (OrthancRestApi::GetContext(call).GetJobsEngine(). - GetRegistry().GetJobOutput(value, mime, job, key)) - { - call.GetOutput().AnswerBuffer(value, mime); - } - else - { - throw OrthancException(ErrorCode_InexistentItem, - "Job has no such output: " + key); - } - } - - - enum JobAction - { - JobAction_Cancel, - JobAction_Pause, - JobAction_Resubmit, - JobAction_Resume - }; - - template - static void ApplyJobAction(RestApiPostCall& call) - { - std::string id = call.GetUriComponent("id", ""); - - bool ok = false; - - switch (action) - { - case JobAction_Cancel: - ok = OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().Cancel(id); - break; - - case JobAction_Pause: - ok = OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().Pause(id); - break; - - case JobAction_Resubmit: - ok = OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().Resubmit(id); - break; - - case JobAction_Resume: - ok = OrthancRestApi::GetContext(call).GetJobsEngine().GetRegistry().Resume(id); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - if (ok) - { - call.GetOutput().AnswerBuffer("{}", MimeType_Json); - } - } - - - static void GetMetricsPrometheus(RestApiGetCall& call) - { -#if ORTHANC_ENABLE_PLUGINS == 1 - OrthancRestApi::GetContext(call).GetPlugins().RefreshMetrics(); -#endif - - static const float MEGA_BYTES = 1024 * 1024; - - ServerContext& context = OrthancRestApi::GetContext(call); - - uint64_t diskSize, uncompressedSize, countPatients, countStudies, countSeries, countInstances; - context.GetIndex().GetGlobalStatistics(diskSize, uncompressedSize, countPatients, - countStudies, countSeries, countInstances); - - unsigned int jobsPending, jobsRunning, jobsSuccess, jobsFailed; - context.GetJobsEngine().GetRegistry().GetStatistics(jobsPending, jobsRunning, jobsSuccess, jobsFailed); - - MetricsRegistry& registry = context.GetMetricsRegistry(); - registry.SetValue("orthanc_disk_size_mb", static_cast(diskSize) / MEGA_BYTES); - registry.SetValue("orthanc_uncompressed_size_mb", static_cast(diskSize) / MEGA_BYTES); - registry.SetValue("orthanc_count_patients", static_cast(countPatients)); - registry.SetValue("orthanc_count_studies", static_cast(countStudies)); - registry.SetValue("orthanc_count_series", static_cast(countSeries)); - registry.SetValue("orthanc_count_instances", static_cast(countInstances)); - registry.SetValue("orthanc_jobs_pending", jobsPending); - registry.SetValue("orthanc_jobs_running", jobsRunning); - registry.SetValue("orthanc_jobs_completed", jobsSuccess + jobsFailed); - registry.SetValue("orthanc_jobs_success", jobsSuccess); - registry.SetValue("orthanc_jobs_failed", jobsFailed); - - std::string s; - registry.ExportPrometheusText(s); - - call.GetOutput().AnswerBuffer(s, MimeType_PrometheusText); - } - - - static void GetMetricsEnabled(RestApiGetCall& call) - { - bool enabled = OrthancRestApi::GetContext(call).GetMetricsRegistry().IsEnabled(); - call.GetOutput().AnswerBuffer(enabled ? "1" : "0", MimeType_PlainText); - } - - - static void PutMetricsEnabled(RestApiPutCall& call) - { - bool enabled; - - std::string body; - call.BodyToString(body); - - if (body == "1") - { - enabled = true; - } - else if (body == "0") - { - enabled = false; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "The HTTP body must be 0 or 1, but found: " + body); - } - - // Success - OrthancRestApi::GetContext(call).GetMetricsRegistry().SetEnabled(enabled); - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - static void GetLogLevel(RestApiGetCall& call) - { - std::string s; - - if (Logging::IsTraceLevelEnabled()) - { - s = LOG_LEVEL_TRACE; - } - else if (Logging::IsInfoLevelEnabled()) - { - s = LOG_LEVEL_VERBOSE; - } - else - { - s = LOG_LEVEL_DEFAULT; - } - - call.GetOutput().AnswerBuffer(s, MimeType_PlainText); - } - - - static void PutLogLevel(RestApiPutCall& call) - { - std::string body; - call.BodyToString(body); - - if (body == LOG_LEVEL_DEFAULT) - { - Logging::EnableInfoLevel(false); - Logging::EnableTraceLevel(false); - } - else if (body == LOG_LEVEL_VERBOSE) - { - Logging::EnableInfoLevel(true); - Logging::EnableTraceLevel(false); - } - else if (body == LOG_LEVEL_TRACE) - { - Logging::EnableInfoLevel(true); - Logging::EnableTraceLevel(true); - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "The log level must be one of the following values: \"" + - std::string(LOG_LEVEL_DEFAULT) + "\", \"" + - std::string(LOG_LEVEL_VERBOSE) + "\", of \"" + - std::string(LOG_LEVEL_TRACE) + "\""); - } - - // Success - LOG(WARNING) << "REST API call has switched the log level to: " << body; - call.GetOutput().AnswerBuffer("", MimeType_PlainText); - } - - - void OrthancRestApi::RegisterSystem() - { - Register("/", ServeRoot); - Register("/system", GetSystemInformation); - Register("/statistics", GetStatistics); - Register("/tools/generate-uid", GenerateUid); - Register("/tools/execute-script", ExecuteScript); - Register("/tools/now", GetNowIsoString); - Register("/tools/now-local", GetNowIsoString); - Register("/tools/dicom-conformance", GetDicomConformanceStatement); - Register("/tools/default-encoding", GetDefaultEncoding); - Register("/tools/default-encoding", SetDefaultEncoding); - Register("/tools/metrics", GetMetricsEnabled); - Register("/tools/metrics", PutMetricsEnabled); - Register("/tools/metrics-prometheus", GetMetricsPrometheus); - Register("/tools/log-level", GetLogLevel); - Register("/tools/log-level", PutLogLevel); - - Register("/plugins", ListPlugins); - Register("/plugins/{id}", GetPlugin); - Register("/plugins/explorer.js", GetOrthancExplorerPlugins); - - Register("/jobs", ListJobs); - Register("/jobs/{id}", GetJobInfo); - Register("/jobs/{id}/cancel", ApplyJobAction); - Register("/jobs/{id}/pause", ApplyJobAction); - Register("/jobs/{id}/resubmit", ApplyJobAction); - Register("/jobs/{id}/resume", ApplyJobAction); - Register("/jobs/{id}/{key}", GetJobOutput); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/PrecompiledHeadersServer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,42 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/PrecompiledHeaders.h" - -#if ORTHANC_USE_PRECOMPILED_HEADERS == 1 - -#include - -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "QueryRetrieveHandler.h" - -#include "OrthancConfiguration.h" - -#include "../Core/DicomNetworking/DicomControlUserConnection.h" -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/Logging.h" -#include "LuaScripting.h" -#include "ServerContext.h" - - -namespace Orthanc -{ - static void FixQueryLua(DicomMap& query, - ServerContext& context, - const std::string& modality) - { - static const char* LUA_CALLBACK = "OutgoingFindRequestFilter"; - - LuaScripting::Lock lock(context.GetLuaScripting()); - - if (lock.GetLua().IsExistingFunction(LUA_CALLBACK)) - { - LuaFunctionCall call(lock.GetLua(), LUA_CALLBACK); - call.PushDicom(query); - call.PushJson(modality); - FromDcmtkBridge::ExecuteToDicom(query, call); - } - } - - - void QueryRetrieveHandler::Invalidate() - { - done_ = false; - answers_.Clear(); - } - - - void QueryRetrieveHandler::Run() - { - if (!done_) - { - // Firstly, fix the content of the query for specific manufacturers - DicomMap fixed; - fixed.Assign(query_); - - // Secondly, possibly fix the query with the user-provider Lua callback - FixQueryLua(fixed, context_, modality_.GetApplicationEntityTitle()); - - { - DicomAssociationParameters params(localAet_, modality_); - DicomControlUserConnection connection(params); - connection.Find(answers_, level_, fixed, findNormalized_); - } - - done_ = true; - } - } - - - QueryRetrieveHandler::QueryRetrieveHandler(ServerContext& context) : - context_(context), - localAet_(context.GetDefaultLocalApplicationEntityTitle()), - done_(false), - level_(ResourceType_Study), - answers_(false), - findNormalized_(true) - { - } - - - void QueryRetrieveHandler::SetModality(const std::string& symbolicName) - { - Invalidate(); - modalityName_ = symbolicName; - - { - OrthancConfiguration::ReaderLock lock; - lock.GetConfiguration().GetDicomModalityUsingSymbolicName(modality_, symbolicName); - } - } - - - void QueryRetrieveHandler::SetLevel(ResourceType level) - { - Invalidate(); - level_ = level; - } - - - void QueryRetrieveHandler::SetQuery(const DicomTag& tag, - const std::string& value) - { - Invalidate(); - query_.SetValue(tag, value, false); - } - - - void QueryRetrieveHandler::CopyStringTag(const DicomMap& from, - const DicomTag& tag) - { - const DicomValue* value = from.TestAndGetValue(tag); - - if (value == NULL || - value->IsNull() || - value->IsBinary()) - { - throw OrthancException(ErrorCode_InexistentTag); - } - else - { - SetQuery(tag, value->GetContent()); - } - } - - - size_t QueryRetrieveHandler::GetAnswersCount() - { - Run(); - return answers_.GetSize(); - } - - - void QueryRetrieveHandler::GetAnswer(DicomMap& target, - size_t i) - { - Run(); - answers_.GetAnswer(i).ExtractDicomSummary(target); - } - - - void QueryRetrieveHandler::SetFindNormalized(bool normalized) - { - Invalidate(); - findNormalized_ = normalized; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/QueryRetrieveHandler.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/DicomNetworking/DicomFindAnswers.h" -#include "../Core/DicomNetworking/RemoteModalityParameters.h" - -namespace Orthanc -{ - class ServerContext; - - class QueryRetrieveHandler : public IDynamicObject - { - private: - ServerContext& context_; - std::string localAet_; - bool done_; - RemoteModalityParameters modality_; - ResourceType level_; - DicomMap query_; - DicomFindAnswers answers_; - std::string modalityName_; - bool findNormalized_; - - void Invalidate(); - - public: - QueryRetrieveHandler(ServerContext& context); - - void SetModality(const std::string& symbolicName); - - const RemoteModalityParameters& GetRemoteModality() const - { - return modality_; - } - - const std::string& GetLocalAet() const - { - return localAet_; - } - - const std::string& GetModalitySymbolicName() const - { - return modalityName_; - } - - void SetLevel(ResourceType level); - - ResourceType GetLevel() const - { - return level_; - } - - void SetQuery(const DicomTag& tag, - const std::string& value); - - const DicomMap& GetQuery() const - { - return query_; - } - - void CopyStringTag(const DicomMap& from, - const DicomTag& tag); - - void Run(); - - size_t GetAnswersCount(); - - void GetAnswer(DicomMap& target, - size_t i); - - bool IsFindNormalized() const - { - return findNormalized_; - } - - void SetFindNormalized(bool normalized); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "DatabaseConstraint.h" - -#include "../../Core/OrthancException.h" - - -namespace Orthanc -{ - namespace Plugins - { -#if ORTHANC_ENABLE_PLUGINS == 1 - OrthancPluginResourceType Convert(ResourceType type) - { - switch (type) - { - case ResourceType_Patient: - return OrthancPluginResourceType_Patient; - - case ResourceType_Study: - return OrthancPluginResourceType_Study; - - case ResourceType_Series: - return OrthancPluginResourceType_Series; - - case ResourceType_Instance: - return OrthancPluginResourceType_Instance; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -#endif - - -#if ORTHANC_ENABLE_PLUGINS == 1 - ResourceType Convert(OrthancPluginResourceType type) - { - switch (type) - { - case OrthancPluginResourceType_Patient: - return ResourceType_Patient; - - case OrthancPluginResourceType_Study: - return ResourceType_Study; - - case OrthancPluginResourceType_Series: - return ResourceType_Series; - - case OrthancPluginResourceType_Instance: - return ResourceType_Instance; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -#endif - - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - OrthancPluginConstraintType Convert(ConstraintType constraint) - { - switch (constraint) - { - case ConstraintType_Equal: - return OrthancPluginConstraintType_Equal; - - case ConstraintType_GreaterOrEqual: - return OrthancPluginConstraintType_GreaterOrEqual; - - case ConstraintType_SmallerOrEqual: - return OrthancPluginConstraintType_SmallerOrEqual; - - case ConstraintType_Wildcard: - return OrthancPluginConstraintType_Wildcard; - - case ConstraintType_List: - return OrthancPluginConstraintType_List; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -#endif - - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - ConstraintType Convert(OrthancPluginConstraintType constraint) - { - switch (constraint) - { - case OrthancPluginConstraintType_Equal: - return ConstraintType_Equal; - - case OrthancPluginConstraintType_GreaterOrEqual: - return ConstraintType_GreaterOrEqual; - - case OrthancPluginConstraintType_SmallerOrEqual: - return ConstraintType_SmallerOrEqual; - - case OrthancPluginConstraintType_Wildcard: - return ConstraintType_Wildcard; - - case OrthancPluginConstraintType_List: - return ConstraintType_List; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -#endif - } - - DatabaseConstraint::DatabaseConstraint(ResourceType level, - const DicomTag& tag, - bool isIdentifier, - ConstraintType type, - const std::vector& values, - bool caseSensitive, - bool mandatory) : - level_(level), - tag_(tag), - isIdentifier_(isIdentifier), - constraintType_(type), - values_(values), - caseSensitive_(caseSensitive), - mandatory_(mandatory) - { - if (type != ConstraintType_List && - values_.size() != 1) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - DatabaseConstraint::DatabaseConstraint(const OrthancPluginDatabaseConstraint& constraint) : - level_(Plugins::Convert(constraint.level)), - tag_(constraint.tagGroup, constraint.tagElement), - isIdentifier_(constraint.isIdentifierTag), - constraintType_(Plugins::Convert(constraint.type)), - caseSensitive_(constraint.isCaseSensitive), - mandatory_(constraint.isMandatory) - { - if (constraintType_ != ConstraintType_List && - constraint.valuesCount != 1) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - values_.resize(constraint.valuesCount); - - for (uint32_t i = 0; i < constraint.valuesCount; i++) - { - assert(constraint.values[i] != NULL); - values_[i].assign(constraint.values[i]); - } - } -#endif - - - const std::string& DatabaseConstraint::GetValue(size_t index) const - { - if (index >= values_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return values_[index]; - } - } - - - const std::string& DatabaseConstraint::GetSingleValue() const - { - if (values_.size() != 1) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return values_[0]; - } - } - - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - void DatabaseConstraint::EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, - std::vector& tmpValues) const - { - memset(&constraint, 0, sizeof(constraint)); - - tmpValues.resize(values_.size()); - - for (size_t i = 0; i < values_.size(); i++) - { - tmpValues[i] = values_[i].c_str(); - } - - constraint.level = Plugins::Convert(level_); - constraint.tagGroup = tag_.GetGroup(); - constraint.tagElement = tag_.GetElement(); - constraint.isIdentifierTag = isIdentifier_; - constraint.isCaseSensitive = caseSensitive_; - constraint.isMandatory = mandatory_; - constraint.type = Plugins::Convert(constraintType_); - constraint.valuesCount = values_.size(); - constraint.values = (tmpValues.empty() ? NULL : &tmpValues[0]); - } -#endif -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseConstraint.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,144 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomFormat/DicomMap.h" -#include "../ServerEnumerations.h" - -#define ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT 0 - -#if ORTHANC_ENABLE_PLUGINS == 1 -# include -# if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 -# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 2) -# undef ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT -# define ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT 1 -# endif -# endif -#endif - -namespace Orthanc -{ - namespace Plugins - { -#if ORTHANC_ENABLE_PLUGINS == 1 - OrthancPluginResourceType Convert(ResourceType type); -#endif - -#if ORTHANC_ENABLE_PLUGINS == 1 - ResourceType Convert(OrthancPluginResourceType type); -#endif - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - OrthancPluginConstraintType Convert(ConstraintType constraint); -#endif - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - ConstraintType Convert(OrthancPluginConstraintType constraint); -#endif - } - - - // This class is also used by the "orthanc-databases" project - class DatabaseConstraint - { - private: - ResourceType level_; - DicomTag tag_; - bool isIdentifier_; - ConstraintType constraintType_; - std::vector values_; - bool caseSensitive_; - bool mandatory_; - - public: - DatabaseConstraint(ResourceType level, - const DicomTag& tag, - bool isIdentifier, - ConstraintType type, - const std::vector& values, - bool caseSensitive, - bool mandatory); - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - DatabaseConstraint(const OrthancPluginDatabaseConstraint& constraint); -#endif - - ResourceType GetLevel() const - { - return level_; - } - - const DicomTag& GetTag() const - { - return tag_; - } - - bool IsIdentifier() const - { - return isIdentifier_; - } - - ConstraintType GetConstraintType() const - { - return constraintType_; - } - - size_t GetValuesCount() const - { - return values_.size(); - } - - const std::string& GetValue(size_t index) const; - - const std::string& GetSingleValue() const; - - bool IsCaseSensitive() const - { - return caseSensitive_; - } - - bool IsMandatory() const - { - return mandatory_; - } - - bool IsMatch(const DicomMap& dicom) const; - -#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 - void EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, - std::vector& tmpValues) const; -#endif - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,316 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "DatabaseLookup.h" - -#include "../ServerToolbox.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/DicomParsing/ToDcmtkBridge.h" -#include "../../Core/OrthancException.h" -#include "../../Core/Toolbox.h" - -namespace Orthanc -{ - DatabaseLookup::~DatabaseLookup() - { - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - delete constraints_[i]; - } - } - - - const DicomTagConstraint& DatabaseLookup::GetConstraint(size_t index) const - { - if (index >= constraints_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - assert(constraints_[index] != NULL); - return *constraints_[index]; - } - } - - - void DatabaseLookup::AddConstraint(DicomTagConstraint* constraint) - { - if (constraint == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else - { - constraints_.push_back(constraint); - } - } - - - bool DatabaseLookup::IsMatch(const DicomMap& value) const - { - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - if (!constraints_[i]->IsMatch(value)) - { - return false; - } - } - - return true; - } - - - bool DatabaseLookup::IsMatch(DcmItem& item, - Encoding encoding, - bool hasCodeExtensions) const - { - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - - const bool isOptionalConstraint = !constraints_[i]->IsMandatory(); - const DcmTagKey tag = ToDcmtkBridge::Convert(constraints_[i]->GetTag()); - - DcmElement* element = NULL; - if (!item.findAndGetElement(tag, element).good()) - { - return isOptionalConstraint; - } - - if (element == NULL) - { - return false; - } - - std::set ignoreTagLength; - std::unique_ptr value(FromDcmtkBridge::ConvertLeafElement - (*element, DicomToJsonFlags_None, - 0, encoding, hasCodeExtensions, ignoreTagLength)); - - // WARNING: Also modify "HierarchicalMatcher::Setup()" if modifying this code - if (value.get() == NULL || - value->IsNull()) - { - return isOptionalConstraint; - } - else if (value->IsBinary() || - !constraints_[i]->IsMatch(value->GetContent())) - { - return false; - } - } - - return true; - } - - - void DatabaseLookup::AddDicomConstraintInternal(const DicomTag& tag, - ValueRepresentation vr, - const std::string& dicomQuery, - bool caseSensitive, - bool mandatoryTag) - { - if ((vr == ValueRepresentation_Date || - vr == ValueRepresentation_DateTime || - vr == ValueRepresentation_Time) && - dicomQuery.find('-') != std::string::npos) - { - /** - * Range matching is only defined for TM, DA and DT value - * representations. This code fixes issues 35 and 37. - * - * Reference: "Range matching is not defined for types of - * Attributes other than dates and times", DICOM PS 3.4, - * C.2.2.2.5 ("Range Matching"). - **/ - size_t separator = dicomQuery.find('-'); - std::string lower = dicomQuery.substr(0, separator); - std::string upper = dicomQuery.substr(separator + 1); - - if (!lower.empty()) - { - AddConstraint(new DicomTagConstraint - (tag, ConstraintType_GreaterOrEqual, lower, caseSensitive, mandatoryTag)); - } - - if (!upper.empty()) - { - AddConstraint(new DicomTagConstraint - (tag, ConstraintType_SmallerOrEqual, upper, caseSensitive, mandatoryTag)); - } - } - else if (tag == DICOM_TAG_MODALITIES_IN_STUDY || - dicomQuery.find('\\') != std::string::npos) - { - DicomTag fixedTag(tag); - - if (tag == DICOM_TAG_MODALITIES_IN_STUDY) - { - // http://www.itk.org/Wiki/DICOM_QueryRetrieve_Explained - // http://dicomiseasy.blogspot.be/2012/01/dicom-queryretrieve-part-i.html - fixedTag = DICOM_TAG_MODALITY; - } - - std::unique_ptr constraint - (new DicomTagConstraint(fixedTag, ConstraintType_List, caseSensitive, mandatoryTag)); - - std::vector items; - Toolbox::TokenizeString(items, dicomQuery, '\\'); - - for (size_t i = 0; i < items.size(); i++) - { - constraint->AddValue(items[i]); - } - - AddConstraint(constraint.release()); - } - else if ( - /** - * New test in Orthanc 1.6.0: Wild card matching is only allowed - * for a subset of value representations: AE, CS, LO, LT, PN, - * SH, ST, UC, UR, UT. - * http://dicom.nema.org/medical/dicom/2019e/output/chtml/part04/sect_C.2.2.2.4.html - **/ - (vr == ValueRepresentation_ApplicationEntity || // AE - vr == ValueRepresentation_CodeString || // CS - vr == ValueRepresentation_LongString || // LO - vr == ValueRepresentation_LongText || // LT - vr == ValueRepresentation_PersonName || // PN - vr == ValueRepresentation_ShortString || // SH - vr == ValueRepresentation_ShortText || // ST - vr == ValueRepresentation_UnlimitedCharacters || // UC - vr == ValueRepresentation_UniversalResource || // UR - vr == ValueRepresentation_UnlimitedText // UT - ) && - (dicomQuery.find('*') != std::string::npos || - dicomQuery.find('?') != std::string::npos)) - { - AddConstraint(new DicomTagConstraint - (tag, ConstraintType_Wildcard, dicomQuery, caseSensitive, mandatoryTag)); - } - else - { - AddConstraint(new DicomTagConstraint - (tag, ConstraintType_Equal, dicomQuery, caseSensitive, mandatoryTag)); - } - } - - - void DatabaseLookup::AddDicomConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitivePN, - bool mandatoryTag) - { - ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(tag); - - if (vr == ValueRepresentation_Sequence) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - /** - * DICOM specifies that searches must always be case sensitive, - * except for tags with a PN value representation. For PN, Orthanc - * uses the configuration option "CaseSensitivePN" to decide - * whether matching is case-sensitive or case-insensitive. - * - * Reference: DICOM PS 3.4 - * - C.2.2.2.1 ("Single Value Matching") - * - C.2.2.2.4 ("Wild Card Matching") - * http://medical.nema.org/Dicom/2011/11_04pu.pdf - * - * "Except for Attributes with a PN Value Representation, only - * entities with values which match exactly the value specified in the - * request shall match. This matching is case-sensitive, i.e., - * sensitive to the exact encoding of the key attribute value in - * character sets where a letter may have multiple encodings (e.g., - * based on its case, its position in a word, or whether it is - * accented) - * - * For Attributes with a PN Value Representation (e.g., Patient Name - * (0010,0010)), an application may perform literal matching that is - * either case-sensitive, or that is insensitive to some or all - * aspects of case, position, accent, or other character encoding - * variants." - * - * (0008,0018) UI SOPInstanceUID => Case-sensitive - * (0008,0050) SH AccessionNumber => Case-sensitive - * (0010,0020) LO PatientID => Case-sensitive - * (0020,000D) UI StudyInstanceUID => Case-sensitive - * (0020,000E) UI SeriesInstanceUID => Case-sensitive - **/ - - if (vr == ValueRepresentation_PersonName) - { - AddDicomConstraintInternal(tag, vr, dicomQuery, caseSensitivePN, mandatoryTag); - } - else - { - AddDicomConstraintInternal(tag, vr, dicomQuery, true /* case sensitive */, mandatoryTag); - } - } - - - void DatabaseLookup::AddRestConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitive, - bool mandatoryTag) - { - AddDicomConstraintInternal(tag, FromDcmtkBridge::LookupValueRepresentation(tag), - dicomQuery, caseSensitive, mandatoryTag); - } - - - bool DatabaseLookup::HasOnlyMainDicomTags() const - { - std::set mainTags; - DicomMap::GetMainDicomTags(mainTags); - - for (size_t i = 0; i < constraints_.size(); i++) - { - assert(constraints_[i] != NULL); - - if (mainTags.find(constraints_[i]->GetTag()) == mainTags.end()) - { - // This is not a main DICOM tag - return false; - } - } - - return true; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DatabaseLookup.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DicomTagConstraint.h" - -class DcmItem; - -namespace Orthanc -{ - class DatabaseLookup : public boost::noncopyable - { - private: - std::vector constraints_; - - void AddDicomConstraintInternal(const DicomTag& tag, - ValueRepresentation vr, - const std::string& dicomQuery, - bool caseSensitive, - bool mandatoryTag); - - void AddConstraint(DicomTagConstraint* constraint); // Takes ownership - - public: - DatabaseLookup() - { - } - - ~DatabaseLookup(); - - void Reserve(size_t n) - { - constraints_.reserve(n); - } - - size_t GetConstraintsCount() const - { - return constraints_.size(); - } - - const DicomTagConstraint& GetConstraint(size_t index) const; - - bool IsMatch(const DicomMap& value) const; - - bool IsMatch(DcmItem& item, - Encoding encoding, - bool hasCodeExtensions) const; - - void AddDicomConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitivePN, - bool mandatoryTag); - - void AddRestConstraint(const DicomTag& tag, - const std::string& dicomQuery, - bool caseSensitive, - bool mandatoryTag); - - bool HasOnlyMainDicomTags() const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,385 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "DicomTagConstraint.h" - -#if defined(ORTHANC_ENABLE_LUA) && ORTHANC_ENABLE_LUA != 0 -# include "../ServerToolbox.h" -#endif - -#include "../../Core/OrthancException.h" -#include "../../Core/Toolbox.h" -#include "DatabaseConstraint.h" - -#include - -namespace Orthanc -{ - class DicomTagConstraint::NormalizedString : public boost::noncopyable - { - private: - const std::string& source_; - bool caseSensitive_; - std::string upper_; - - public: - NormalizedString(const std::string& source, - bool caseSensitive) : - source_(source), - caseSensitive_(caseSensitive) - { - if (!caseSensitive_) - { - upper_ = Toolbox::ToUpperCaseWithAccents(source); - } - } - - const std::string& GetValue() const - { - if (caseSensitive_) - { - return source_; - } - else - { - return upper_; - } - } - }; - - - class DicomTagConstraint::RegularExpression : public boost::noncopyable - { - private: - boost::regex regex_; - - public: - RegularExpression(const std::string& source, - bool caseSensitive) - { - NormalizedString normalized(source, caseSensitive); - regex_ = boost::regex(Toolbox::WildcardToRegularExpression(normalized.GetValue())); - } - - const boost::regex& GetValue() const - { - return regex_; - } - }; - - - void DicomTagConstraint::AssignSingleValue(const std::string& value) - { - if (constraintType_ != ConstraintType_Wildcard && - (value.find('*') != std::string::npos || - value.find('?') != std::string::npos)) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Wildcards are not allowed on tag " + tag_.Format()); - } - - if (constraintType_ == ConstraintType_Equal || - constraintType_ == ConstraintType_SmallerOrEqual || - constraintType_ == ConstraintType_GreaterOrEqual || - constraintType_ == ConstraintType_Wildcard) - { - values_.clear(); - values_.insert(value); - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - DicomTagConstraint::DicomTagConstraint(const DicomTag& tag, - ConstraintType type, - const std::string& value, - bool caseSensitive, - bool mandatory) : - tag_(tag), - constraintType_(type), - caseSensitive_(caseSensitive), - mandatory_(mandatory) - { - AssignSingleValue(value); - } - - - DicomTagConstraint::DicomTagConstraint(const DicomTag& tag, - ConstraintType type, - bool caseSensitive, - bool mandatory) : - tag_(tag), - constraintType_(type), - caseSensitive_(caseSensitive), - mandatory_(mandatory) - { - if (type != ConstraintType_List) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - DicomTagConstraint::DicomTagConstraint(const DatabaseConstraint& constraint) : - tag_(constraint.GetTag()), - constraintType_(constraint.GetConstraintType()), - caseSensitive_(constraint.IsCaseSensitive()), - mandatory_(constraint.IsMandatory()) - { -#if defined(ORTHANC_ENABLE_LUA) && ORTHANC_ENABLE_LUA != 0 - assert(constraint.IsIdentifier() == - ServerToolbox::IsIdentifier(constraint.GetTag(), constraint.GetLevel())); -#endif - - if (constraint.IsIdentifier()) - { - // This conversion is only available for main DICOM tags, not for identifers - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (constraintType_ == ConstraintType_List) - { - for (size_t i = 0; i < constraint.GetValuesCount(); i++) - { - AddValue(constraint.GetValue(i)); - } - } - else - { - AssignSingleValue(constraint.GetSingleValue()); - } - } - - - void DicomTagConstraint::AddValue(const std::string& value) - { - if (constraintType_ != ConstraintType_List) - { - throw OrthancException(ErrorCode_BadParameterType); - } - else - { - values_.insert(value); - } - } - - - const std::string& DicomTagConstraint::GetValue() const - { - if (constraintType_ == ConstraintType_List) - { - throw OrthancException(ErrorCode_BadParameterType); - } - else if (values_.size() != 1) - { - throw OrthancException(ErrorCode_InternalError); - } - else - { - return *values_.begin(); - } - } - - - bool DicomTagConstraint::IsMatch(const std::string& value) - { - NormalizedString source(value, caseSensitive_); - - switch (constraintType_) - { - case ConstraintType_Equal: - { - NormalizedString reference(GetValue(), caseSensitive_); - return source.GetValue() == reference.GetValue(); - } - - case ConstraintType_SmallerOrEqual: - { - NormalizedString reference(GetValue(), caseSensitive_); - return source.GetValue() <= reference.GetValue(); - } - - case ConstraintType_GreaterOrEqual: - { - NormalizedString reference(GetValue(), caseSensitive_); - return source.GetValue() >= reference.GetValue(); - } - - case ConstraintType_Wildcard: - { - if (regex_.get() == NULL) - { - regex_.reset(new RegularExpression(GetValue(), caseSensitive_)); - } - - return boost::regex_match(source.GetValue(), regex_->GetValue()); - } - - case ConstraintType_List: - { - for (std::set::const_iterator - it = values_.begin(); it != values_.end(); ++it) - { - NormalizedString reference(*it, caseSensitive_); - if (source.GetValue() == reference.GetValue()) - { - return true; - } - } - - return false; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - bool DicomTagConstraint::IsMatch(const DicomMap& value) - { - const DicomValue* tmp = value.TestAndGetValue(tag_); - - if (tmp == NULL || - tmp->IsNull()) - { - if (mandatory_) - { - return false; - } - else - { - return true; - } - } - else if (tmp->IsBinary()) - { - return false; - } - else - { - return IsMatch(tmp->GetContent()); - } - } - - - std::string DicomTagConstraint::Format() const - { - switch (constraintType_) - { - case ConstraintType_Equal: - return tag_.Format() + " == " + GetValue(); - - case ConstraintType_SmallerOrEqual: - return tag_.Format() + " <= " + GetValue(); - - case ConstraintType_GreaterOrEqual: - return tag_.Format() + " >= " + GetValue(); - - case ConstraintType_Wildcard: - return tag_.Format() + " ~~ " + GetValue(); - - case ConstraintType_List: - { - std::string s = tag_.Format() + " IN [ "; - - bool first = true; - for (std::set::const_iterator - it = values_.begin(); it != values_.end(); ++it) - { - if (first) - { - first = false; - } - else - { - s += ", "; - } - - s += *it; - } - - return s + "]"; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - DatabaseConstraint DicomTagConstraint::ConvertToDatabaseConstraint(ResourceType level, - DicomTagType tagType) const - { - bool isIdentifier, caseSensitive; - - switch (tagType) - { - case DicomTagType_Identifier: - isIdentifier = true; - caseSensitive = true; - break; - - case DicomTagType_Main: - isIdentifier = false; - caseSensitive = IsCaseSensitive(); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::vector values; - values.reserve(values_.size()); - - for (std::set::const_iterator - it = values_.begin(); it != values_.end(); ++it) - { - if (isIdentifier) - { - values.push_back(ServerToolbox::NormalizeIdentifier(*it)); - } - else - { - values.push_back(*it); - } - } - - return DatabaseConstraint(level, tag_, isIdentifier, constraintType_, - values, caseSensitive, mandatory_); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/DicomTagConstraint.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../ServerEnumerations.h" -#include "../../Core/DicomFormat/DicomMap.h" -#include "DatabaseConstraint.h" - -#include - -namespace Orthanc -{ - class DicomTagConstraint : public boost::noncopyable - { - private: - class NormalizedString; - class RegularExpression; - - DicomTag tag_; - ConstraintType constraintType_; - std::set values_; - bool caseSensitive_; - bool mandatory_; - - boost::shared_ptr regex_; - - void AssignSingleValue(const std::string& value); - - public: - DicomTagConstraint(const DicomTag& tag, - ConstraintType type, - const std::string& value, - bool caseSensitive, - bool mandatory); - - // For list search - DicomTagConstraint(const DicomTag& tag, - ConstraintType type, - bool caseSensitive, - bool mandatory); - - DicomTagConstraint(const DatabaseConstraint& constraint); - - const DicomTag& GetTag() const - { - return tag_; - } - - ConstraintType GetConstraintType() const - { - return constraintType_; - } - - bool IsCaseSensitive() const - { - return caseSensitive_; - } - - void SetCaseSensitive(bool caseSensitive) - { - caseSensitive_ = caseSensitive; - } - - bool IsMandatory() const - { - return mandatory_; - } - - void AddValue(const std::string& value); - - const std::string& GetValue() const; - - const std::set& GetValues() const - { - return values_; - } - - bool IsMatch(const std::string& value); - - bool IsMatch(const DicomMap& value); - - std::string Format() const; - - DatabaseConstraint ConvertToDatabaseConstraint(ResourceType level, - DicomTagType tagType) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,332 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "HierarchicalMatcher.h" - -#include "../../Core/Logging.h" -#include "../../Core/OrthancException.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/DicomParsing/ToDcmtkBridge.h" -#include "../OrthancConfiguration.h" - -#include - -namespace Orthanc -{ - HierarchicalMatcher::HierarchicalMatcher(ParsedDicomFile& query) - { - bool caseSensitivePN; - - { - OrthancConfiguration::ReaderLock lock; - caseSensitivePN = lock.GetConfiguration().GetBooleanParameter("CaseSensitivePN", false); - } - - bool hasCodeExtensions; - Encoding encoding = query.DetectEncoding(hasCodeExtensions); - Setup(*query.GetDcmtkObject().getDataset(), caseSensitivePN, encoding, hasCodeExtensions); - } - - - HierarchicalMatcher::~HierarchicalMatcher() - { - for (Sequences::iterator it = sequences_.begin(); - it != sequences_.end(); ++it) - { - if (it->second != NULL) - { - delete it->second; - } - } - } - - - void HierarchicalMatcher::Setup(DcmItem& dataset, - bool caseSensitivePN, - Encoding encoding, - bool hasCodeExtensions) - { - for (unsigned long i = 0; i < dataset.card(); i++) - { - DcmElement* element = dataset.getElement(i); - if (element == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); - if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET || // Ignore encoding - tag.GetElement() == 0x0000) // Ignore all "Group Length" tags - { - continue; - } - - if (flatTags_.find(tag) != flatTags_.end() || - sequences_.find(tag) != sequences_.end()) - { - // A constraint already exists on this tag - throw OrthancException(ErrorCode_BadRequest); - } - - if (FromDcmtkBridge::LookupValueRepresentation(tag) == ValueRepresentation_Sequence) - { - DcmSequenceOfItems& sequence = dynamic_cast(*element); - - if (sequence.card() == 0 || - (sequence.card() == 1 && sequence.getItem(0)->card() == 0)) - { - // Universal matching of a sequence - sequences_[tag] = NULL; - } - else if (sequence.card() == 1) - { - sequences_[tag] = new HierarchicalMatcher(*sequence.getItem(0), caseSensitivePN, encoding, hasCodeExtensions); - } - else - { - throw OrthancException(ErrorCode_BadRequest); - } - } - else - { - flatTags_.insert(tag); - - std::set ignoreTagLength; - std::unique_ptr value(FromDcmtkBridge::ConvertLeafElement - (*element, DicomToJsonFlags_None, - 0, encoding, hasCodeExtensions, ignoreTagLength)); - - // WARNING: Also modify "DatabaseLookup::IsMatch()" if modifying this code - if (value.get() == NULL || - value->IsNull()) - { - // This is an universal constraint - } - else if (value->IsBinary()) - { - if (!value->GetContent().empty()) - { - LOG(WARNING) << "This C-Find modality worklist query contains a non-empty tag (" - << tag.Format() << ") with UN (unknown) value representation. " - << "It will be ignored."; - } - } - else if (value->GetContent().empty()) - { - // This is an universal matcher - } - else - { - flatConstraints_.AddDicomConstraint - (tag, value->GetContent(), caseSensitivePN, true /* mandatory */); - } - } - } - } - - - std::string HierarchicalMatcher::Format(const std::string& prefix) const - { - std::string s; - - std::set tags; - for (size_t i = 0; i < flatConstraints_.GetConstraintsCount(); i++) - { - const DicomTagConstraint& c = flatConstraints_.GetConstraint(i); - - s += c.Format() + "\n"; - tags.insert(c.GetTag()); - } - - // Loop over the universal constraints - for (std::set::const_iterator it = flatTags_.begin(); - it != flatTags_.end(); ++it) - { - if (tags.find(*it) == tags.end()) - { - s += prefix + it->Format() + " == *\n"; - } - } - - for (Sequences::const_iterator it = sequences_.begin(); - it != sequences_.end(); ++it) - { - s += prefix + it->first.Format() + " "; - - if (it->second == NULL) - { - s += "*\n"; - } - else - { - s += "Sequence:\n" + it->second->Format(prefix + " "); - } - } - - return s; - } - - - bool HierarchicalMatcher::Match(ParsedDicomFile& dicom) const - { - bool hasCodeExtensions; - Encoding encoding = dicom.DetectEncoding(hasCodeExtensions); - - return MatchInternal(*dicom.GetDcmtkObject().getDataset(), - encoding, hasCodeExtensions); - } - - - bool HierarchicalMatcher::MatchInternal(DcmItem& item, - Encoding encoding, - bool hasCodeExtensions) const - { - if (!flatConstraints_.IsMatch(item, encoding, hasCodeExtensions)) - { - return false; - } - - for (Sequences::const_iterator it = sequences_.begin(); - it != sequences_.end(); ++it) - { - if (it->second != NULL) - { - DcmTagKey tag = ToDcmtkBridge::Convert(it->first); - - DcmSequenceOfItems* sequence = NULL; - if (!item.findAndGetSequence(tag, sequence).good() || - sequence == NULL) - { - continue; - } - - bool match = false; - - for (unsigned long i = 0; i < sequence->card(); i++) - { - if (it->second->MatchInternal(*sequence->getItem(i), encoding, hasCodeExtensions)) - { - match = true; - break; - } - } - - if (!match) - { - return false; - } - } - } - - return true; - } - - - DcmDataset* HierarchicalMatcher::ExtractInternal(DcmItem& source, - Encoding encoding, - bool hasCodeExtensions) const - { - std::unique_ptr target(new DcmDataset); - - for (std::set::const_iterator it = flatTags_.begin(); - it != flatTags_.end(); ++it) - { - DcmTagKey tag = ToDcmtkBridge::Convert(*it); - - DcmElement* element = NULL; - if (source.findAndGetElement(tag, element).good() && - element != NULL) - { - if (it->IsPrivate()) - { - throw OrthancException(ErrorCode_NotImplemented, - "Not applicable to private tags: " + it->Format()); - } - - std::unique_ptr cloned(FromDcmtkBridge::CreateElementForTag(*it, "" /* no private creator */)); - cloned->copyFrom(*element); - target->insert(cloned.release()); - } - } - - for (Sequences::const_iterator it = sequences_.begin(); - it != sequences_.end(); ++it) - { - DcmTagKey tag = ToDcmtkBridge::Convert(it->first); - - DcmSequenceOfItems* sequence = NULL; - if (source.findAndGetSequence(tag, sequence).good() && - sequence != NULL) - { - std::unique_ptr cloned(new DcmSequenceOfItems(tag)); - - for (unsigned long i = 0; i < sequence->card(); i++) - { - if (it->second == NULL) - { - cloned->append(new DcmItem(*sequence->getItem(i))); - } - else if (it->second->MatchInternal(*sequence->getItem(i), encoding, hasCodeExtensions)) // TODO Might be optimized - { - // It is necessary to encapsulate the child dataset into a - // "DcmItem" object before it can be included in a - // sequence. Otherwise, "dciodvfy" reports an error "Bad - // tag in sequence - Expecting Item or Sequence Delimiter." - std::unique_ptr child(it->second->ExtractInternal(*sequence->getItem(i), encoding, hasCodeExtensions)); - cloned->append(new DcmItem(*child)); - } - } - - target->insert(cloned.release()); - } - } - - return target.release(); - } - - - ParsedDicomFile* HierarchicalMatcher::Extract(ParsedDicomFile& dicom) const - { - bool hasCodeExtensions; - Encoding encoding = dicom.DetectEncoding(hasCodeExtensions); - - std::unique_ptr dataset(ExtractInternal(*dicom.GetDcmtkObject().getDataset(), - encoding, hasCodeExtensions)); - - std::unique_ptr result(new ParsedDicomFile(*dataset)); - result->SetEncoding(encoding); - - return result.release(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/HierarchicalMatcher.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "DatabaseLookup.h" -#include "../../Core/DicomParsing/ParsedDicomFile.h" - -class DcmItem; - -namespace Orthanc -{ - class HierarchicalMatcher : public boost::noncopyable - { - private: - typedef std::map Sequences; - - std::set flatTags_; - DatabaseLookup flatConstraints_; - Sequences sequences_; - - void Setup(DcmItem& query, - bool caseSensitivePN, - Encoding encoding, - bool hasCodeExtensions); - - HierarchicalMatcher(DcmItem& query, - bool caseSensitivePN, - Encoding encoding, - bool hasCodeExtensions) - { - Setup(query, caseSensitivePN, encoding, hasCodeExtensions); - } - - bool MatchInternal(DcmItem& dicom, - Encoding encoding, - bool hasCodeExtensions) const; - - DcmDataset* ExtractInternal(DcmItem& dicom, - Encoding encoding, - bool hasCodeExtensions) const; - - public: - HierarchicalMatcher(ParsedDicomFile& query); - - ~HierarchicalMatcher(); - - std::string Format(const std::string& prefix = "") const; - - bool Match(ParsedDicomFile& dicom) const; - - ParsedDicomFile* Extract(ParsedDicomFile& dicom) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,343 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "ISqlLookupFormatter.h" - -#include "../../Core/OrthancException.h" -#include "DatabaseConstraint.h" - -namespace Orthanc -{ - static std::string FormatLevel(ResourceType level) - { - switch (level) - { - case ResourceType_Patient: - return "patients"; - - case ResourceType_Study: - return "studies"; - - case ResourceType_Series: - return "series"; - - case ResourceType_Instance: - return "instances"; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - - static bool FormatComparison(std::string& target, - ISqlLookupFormatter& formatter, - const DatabaseConstraint& constraint, - size_t index) - { - std::string tag = "t" + boost::lexical_cast(index); - - std::string comparison; - - switch (constraint.GetConstraintType()) - { - case ConstraintType_Equal: - case ConstraintType_SmallerOrEqual: - case ConstraintType_GreaterOrEqual: - { - std::string op; - switch (constraint.GetConstraintType()) - { - case ConstraintType_Equal: - op = "="; - break; - - case ConstraintType_SmallerOrEqual: - op = "<="; - break; - - case ConstraintType_GreaterOrEqual: - op = ">="; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::string parameter = formatter.GenerateParameter(constraint.GetSingleValue()); - - if (constraint.IsCaseSensitive()) - { - comparison = tag + ".value " + op + " " + parameter; - } - else - { - comparison = "lower(" + tag + ".value) " + op + " lower(" + parameter + ")"; - } - - break; - } - - case ConstraintType_List: - { - for (size_t i = 0; i < constraint.GetValuesCount(); i++) - { - if (!comparison.empty()) - { - comparison += ", "; - } - - std::string parameter = formatter.GenerateParameter(constraint.GetValue(i)); - - if (constraint.IsCaseSensitive()) - { - comparison += parameter; - } - else - { - comparison += "lower(" + parameter + ")"; - } - } - - if (constraint.IsCaseSensitive()) - { - comparison = tag + ".value IN (" + comparison + ")"; - } - else - { - comparison = "lower(" + tag + ".value) IN (" + comparison + ")"; - } - - break; - } - - case ConstraintType_Wildcard: - { - const std::string value = constraint.GetSingleValue(); - - if (value == "*") - { - if (!constraint.IsMandatory()) - { - // Universal constraint on an optional tag, ignore it - return false; - } - } - else - { - std::string escaped; - escaped.reserve(value.size()); - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == '*') - { - escaped += "%"; - } - else if (value[i] == '?') - { - escaped += "_"; - } - else if (value[i] == '%') - { - escaped += "\\%"; - } - else if (value[i] == '_') - { - escaped += "\\_"; - } - else if (value[i] == '\\') - { - escaped += "\\\\"; - } - else - { - escaped += value[i]; - } - } - - std::string parameter = formatter.GenerateParameter(escaped); - - if (constraint.IsCaseSensitive()) - { - comparison = (tag + ".value LIKE " + parameter + " " + - formatter.FormatWildcardEscape()); - } - else - { - comparison = ("lower(" + tag + ".value) LIKE lower(" + - parameter + ") " + formatter.FormatWildcardEscape()); - } - } - - break; - } - - default: - return false; - } - - if (constraint.IsMandatory()) - { - target = comparison; - } - else if (comparison.empty()) - { - target = tag + ".value IS NULL"; - } - else - { - target = tag + ".value IS NULL OR " + comparison; - } - - return true; - } - - - static void FormatJoin(std::string& target, - const DatabaseConstraint& constraint, - size_t index) - { - std::string tag = "t" + boost::lexical_cast(index); - - if (constraint.IsMandatory()) - { - target = " INNER JOIN "; - } - else - { - target = " LEFT JOIN "; - } - - if (constraint.IsIdentifier()) - { - target += "DicomIdentifiers "; - } - else - { - target += "MainDicomTags "; - } - - target += (tag + " ON " + tag + ".id = " + FormatLevel(constraint.GetLevel()) + - ".internalId AND " + tag + ".tagGroup = " + - boost::lexical_cast(constraint.GetTag().GetGroup()) + - " AND " + tag + ".tagElement = " + - boost::lexical_cast(constraint.GetTag().GetElement())); - } - - - void ISqlLookupFormatter::Apply(std::string& sql, - ISqlLookupFormatter& formatter, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit) - { - assert(ResourceType_Patient < ResourceType_Study && - ResourceType_Study < ResourceType_Series && - ResourceType_Series < ResourceType_Instance); - - ResourceType upperLevel = queryLevel; - ResourceType lowerLevel = queryLevel; - - for (size_t i = 0; i < lookup.size(); i++) - { - ResourceType level = lookup[i].GetLevel(); - - if (level < upperLevel) - { - upperLevel = level; - } - - if (level > lowerLevel) - { - lowerLevel = level; - } - } - - assert(upperLevel <= queryLevel && - queryLevel <= lowerLevel); - - std::string joins, comparisons; - - size_t count = 0; - - for (size_t i = 0; i < lookup.size(); i++) - { - std::string comparison; - - if (FormatComparison(comparison, formatter, lookup[i], count)) - { - std::string join; - FormatJoin(join, lookup[i], count); - joins += join; - - if (!comparison.empty()) - { - comparisons += " AND " + comparison; - } - - count ++; - } - } - - sql = ("SELECT " + - FormatLevel(queryLevel) + ".publicId, " + - FormatLevel(queryLevel) + ".internalId" + - " FROM Resources AS " + FormatLevel(queryLevel)); - - for (int level = queryLevel - 1; level >= upperLevel; level--) - { - sql += (" INNER JOIN Resources " + - FormatLevel(static_cast(level)) + " ON " + - FormatLevel(static_cast(level)) + ".internalId=" + - FormatLevel(static_cast(level + 1)) + ".parentId"); - } - - for (int level = queryLevel + 1; level <= lowerLevel; level++) - { - sql += (" INNER JOIN Resources " + - FormatLevel(static_cast(level)) + " ON " + - FormatLevel(static_cast(level - 1)) + ".internalId=" + - FormatLevel(static_cast(level)) + ".parentId"); - } - - sql += (joins + " WHERE " + FormatLevel(queryLevel) + ".resourceType = " + - formatter.FormatResourceType(queryLevel) + comparisons); - - if (limit != 0) - { - sql += " LIMIT " + boost::lexical_cast(limit); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/Search/ISqlLookupFormatter.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/Enumerations.h" - -#include -#include - -namespace Orthanc -{ - class DatabaseConstraint; - - // This class is also used by the "orthanc-databases" project - class ISqlLookupFormatter : public boost::noncopyable - { - public: - virtual ~ISqlLookupFormatter() - { - } - - virtual std::string GenerateParameter(const std::string& value) = 0; - - virtual std::string FormatResourceType(ResourceType level) = 0; - - virtual std::string FormatWildcardEscape() = 0; - - static void Apply(std::string& sql, - ISqlLookupFormatter& formatter, - const std::vector& lookup, - ResourceType queryLevel, - size_t limit); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1361 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "ServerContext.h" - -#include "../Core/DicomParsing/Internals/DicomImageDecoder.h" -#include "../Core/Cache/SharedArchive.h" -#include "../Core/DicomParsing/DcmtkTranscoder.h" -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/FileStorage/StorageAccessor.h" -#include "../Core/HttpServer/FilesystemHttpSender.h" -#include "../Core/HttpServer/HttpStreamTranscoder.h" -#include "../Core/JobsEngine/SetOfInstancesJob.h" -#include "../Core/Logging.h" -#include "../Core/MetricsRegistry.h" -#include "../Plugins/Engine/OrthancPlugins.h" - -#include "OrthancConfiguration.h" -#include "OrthancRestApi/OrthancRestApi.h" -#include "Search/DatabaseLookup.h" -#include "ServerJobs/OrthancJobUnserializer.h" -#include "ServerToolbox.h" -#include "StorageCommitmentReports.h" - -#include -#include - - - -#define ENABLE_DICOM_CACHE 1 - -static const size_t DICOM_CACHE_SIZE = 2; - -/** - * IMPORTANT: We make the assumption that the same instance of - * FileStorage can be accessed from multiple threads. This seems OK - * since the filesystem implements the required locking mechanisms, - * but maybe a read-writer lock on the "FileStorage" could be - * useful. Conversely, "ServerIndex" already implements mutex-based - * locking. - **/ - -namespace Orthanc -{ - void ServerContext::ChangeThread(ServerContext* that, - unsigned int sleepDelay) - { - while (!that->done_) - { - std::unique_ptr obj(that->pendingChanges_.Dequeue(sleepDelay)); - - if (obj.get() != NULL) - { - const ServerIndexChange& change = dynamic_cast(*obj.get()); - - boost::shared_lock lock(that->listenersMutex_); - for (ServerListeners::iterator it = that->listeners_.begin(); - it != that->listeners_.end(); ++it) - { - try - { - try - { - it->GetListener().SignalChange(change); - } - catch (std::bad_alloc&) - { - LOG(ERROR) << "Not enough memory while signaling a change"; - } - catch (...) - { - throw OrthancException(ErrorCode_InternalError); - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Error in the " << it->GetDescription() - << " callback while signaling a change: " << e.What() - << " (code " << e.GetErrorCode() << ")"; - } - } - } - } - } - - - void ServerContext::SaveJobsThread(ServerContext* that, - unsigned int sleepDelay) - { - static const boost::posix_time::time_duration PERIODICITY = - boost::posix_time::seconds(10); - - boost::posix_time::ptime next = - boost::posix_time::microsec_clock::universal_time() + PERIODICITY; - - while (!that->done_) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(sleepDelay)); - - if (that->haveJobsChanged_ || - boost::posix_time::microsec_clock::universal_time() >= next) - { - that->haveJobsChanged_ = false; - that->SaveJobsEngine(); - next = boost::posix_time::microsec_clock::universal_time() + PERIODICITY; - } - } - } - - - void ServerContext::SignalJobSubmitted(const std::string& jobId) - { - haveJobsChanged_ = true; - mainLua_.SignalJobSubmitted(jobId); - } - - - void ServerContext::SignalJobSuccess(const std::string& jobId) - { - haveJobsChanged_ = true; - mainLua_.SignalJobSuccess(jobId); - } - - - void ServerContext::SignalJobFailure(const std::string& jobId) - { - haveJobsChanged_ = true; - mainLua_.SignalJobFailure(jobId); - } - - - void ServerContext::SetupJobsEngine(bool unitTesting, - bool loadJobsFromDatabase) - { - if (loadJobsFromDatabase) - { - std::string serialized; - if (index_.LookupGlobalProperty(serialized, GlobalProperty_JobsRegistry)) - { - LOG(WARNING) << "Reloading the jobs from the last execution of Orthanc"; - OrthancJobUnserializer unserializer(*this); - - try - { - jobsEngine_.LoadRegistryFromString(unserializer, serialized); - } - catch (OrthancException& e) - { - LOG(WARNING) << "Cannot unserialize the jobs engine, starting anyway: " << e.What(); - } - } - else - { - LOG(INFO) << "The last execution of Orthanc has archived no job"; - } - } - else - { - LOG(INFO) << "Not reloading the jobs from the last execution of Orthanc"; - } - - jobsEngine_.GetRegistry().SetObserver(*this); - jobsEngine_.Start(); - isJobsEngineUnserialized_ = true; - - saveJobsThread_ = boost::thread(SaveJobsThread, this, (unitTesting ? 20 : 100)); - } - - - void ServerContext::SaveJobsEngine() - { - if (saveJobs_) - { - VLOG(1) << "Serializing the content of the jobs engine"; - - try - { - Json::Value value; - jobsEngine_.GetRegistry().Serialize(value); - - Json::FastWriter writer; - std::string serialized = writer.write(value); - - index_.SetGlobalProperty(GlobalProperty_JobsRegistry, serialized); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Cannot serialize the jobs engine: " << e.What(); - } - } - } - - - ServerContext::ServerContext(IDatabaseWrapper& database, - IStorageArea& area, - bool unitTesting, - size_t maxCompletedJobs) : - index_(*this, database, (unitTesting ? 20 : 500)), - area_(area), - compressionEnabled_(false), - storeMD5_(true), - provider_(*this), - dicomCache_(provider_, DICOM_CACHE_SIZE), - mainLua_(*this), - filterLua_(*this), - luaListener_(*this), - jobsEngine_(maxCompletedJobs), -#if ORTHANC_ENABLE_PLUGINS == 1 - plugins_(NULL), -#endif - done_(false), - haveJobsChanged_(false), - isJobsEngineUnserialized_(false), - metricsRegistry_(new MetricsRegistry), - isHttpServerSecure_(true), - isExecuteLuaEnabled_(false), - overwriteInstances_(false), - dcmtkTranscoder_(new DcmtkTranscoder), - isIngestTranscoding_(false) - { - try - { - unsigned int lossyQuality; - - { - OrthancConfiguration::ReaderLock lock; - - queryRetrieveArchive_.reset( - new SharedArchive(lock.GetConfiguration().GetUnsignedIntegerParameter("QueryRetrieveSize", 100))); - mediaArchive_.reset( - new SharedArchive(lock.GetConfiguration().GetUnsignedIntegerParameter("MediaArchiveSize", 1))); - defaultLocalAet_ = lock.GetConfiguration().GetStringParameter("DicomAet", "ORTHANC"); - jobsEngine_.SetWorkersCount(lock.GetConfiguration().GetUnsignedIntegerParameter("ConcurrentJobs", 2)); - saveJobs_ = lock.GetConfiguration().GetBooleanParameter("SaveJobs", true); - metricsRegistry_->SetEnabled(lock.GetConfiguration().GetBooleanParameter("MetricsEnabled", true)); - - // New configuration options in Orthanc 1.5.1 - findStorageAccessMode_ = StringToFindStorageAccessMode(lock.GetConfiguration().GetStringParameter("StorageAccessOnFind", "Always")); - limitFindInstances_ = lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindInstances", 0); - limitFindResults_ = lock.GetConfiguration().GetUnsignedIntegerParameter("LimitFindResults", 0); - - // New configuration option in Orthanc 1.6.0 - storageCommitmentReports_.reset(new StorageCommitmentReports(lock.GetConfiguration().GetUnsignedIntegerParameter("StorageCommitmentReportsSize", 100))); - - // New options in Orthanc 1.7.0 - transcodeDicomProtocol_ = lock.GetConfiguration().GetBooleanParameter("TranscodeDicomProtocol", true); - builtinDecoderTranscoderOrder_ = StringToBuiltinDecoderTranscoderOrder(lock.GetConfiguration().GetStringParameter("BuiltinDecoderTranscoderOrder", "After")); - lossyQuality = lock.GetConfiguration().GetUnsignedIntegerParameter("DicomLossyTranscodingQuality", 90); - - std::string s; - if (lock.GetConfiguration().LookupStringParameter(s, "IngestTranscoding")) - { - if (LookupTransferSyntax(ingestTransferSyntax_, s)) - { - isIngestTranscoding_ = true; - LOG(WARNING) << "Incoming DICOM instances will automatically be transcoded to " - << "transfer syntax: " << GetTransferSyntaxUid(ingestTransferSyntax_); - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Unknown transfer syntax for ingest transcoding: " + s); - } - } - else - { - isIngestTranscoding_ = false; - LOG(INFO) << "Automated transcoding of incoming DICOM instances is disabled"; - } - } - - jobsEngine_.SetThreadSleep(unitTesting ? 20 : 200); - - listeners_.push_back(ServerListener(luaListener_, "Lua")); - changeThread_ = boost::thread(ChangeThread, this, (unitTesting ? 20 : 100)); - - dynamic_cast(*dcmtkTranscoder_).SetLossyQuality(lossyQuality); - } - catch (OrthancException&) - { - Stop(); - throw; - } - } - - - - ServerContext::~ServerContext() - { - if (!done_) - { - LOG(ERROR) << "INTERNAL ERROR: ServerContext::Stop() should be invoked manually to avoid mess in the destruction order!"; - Stop(); - } - } - - - void ServerContext::Stop() - { - if (!done_) - { - { - boost::unique_lock lock(listenersMutex_); - listeners_.clear(); - } - - done_ = true; - - if (changeThread_.joinable()) - { - changeThread_.join(); - } - - if (saveJobsThread_.joinable()) - { - saveJobsThread_.join(); - } - - jobsEngine_.GetRegistry().ResetObserver(); - - if (isJobsEngineUnserialized_) - { - // Avoid losing jobs if the JobsRegistry cannot be unserialized - SaveJobsEngine(); - } - - // Do not change the order below! - jobsEngine_.Stop(); - index_.Stop(); - } - } - - - void ServerContext::SetCompressionEnabled(bool enabled) - { - if (enabled) - LOG(WARNING) << "Disk compression is enabled"; - else - LOG(WARNING) << "Disk compression is disabled"; - - compressionEnabled_ = enabled; - } - - - void ServerContext::RemoveFile(const std::string& fileUuid, - FileContentType type) - { - StorageAccessor accessor(area_, GetMetricsRegistry()); - accessor.Remove(fileUuid, type); - } - - - StoreStatus ServerContext::StoreAfterTranscoding(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode) - { - bool overwrite; - switch (mode) - { - case StoreInstanceMode_Default: - overwrite = overwriteInstances_; - break; - - case StoreInstanceMode_OverwriteDuplicate: - overwrite = true; - break; - - case StoreInstanceMode_IgnoreDuplicate: - overwrite = false; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - try - { - MetricsRegistry::Timer timer(GetMetricsRegistry(), "orthanc_store_dicom_duration_ms"); - StorageAccessor accessor(area_, GetMetricsRegistry()); - - resultPublicId = dicom.GetHasher().HashInstance(); - - Json::Value simplifiedTags; - ServerToolbox::SimplifyTags(simplifiedTags, dicom.GetJson(), DicomToJsonFormat_Human); - - // Test if the instance must be filtered out - bool accepted = true; - - { - boost::shared_lock lock(listenersMutex_); - - for (ServerListeners::iterator it = listeners_.begin(); it != listeners_.end(); ++it) - { - try - { - if (!it->GetListener().FilterIncomingInstance(dicom, simplifiedTags)) - { - accepted = false; - break; - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Error in the " << it->GetDescription() - << " callback while receiving an instance: " << e.What() - << " (code " << e.GetErrorCode() << ")"; - throw; - } - } - } - - if (!accepted) - { - LOG(INFO) << "An incoming instance has been discarded by the filter"; - return StoreStatus_FilteredOut; - } - - { - // Remove the file from the DicomCache (useful if - // "OverwriteInstances" is set to "true") - boost::mutex::scoped_lock lock(dicomCacheMutex_); - dicomCache_.Invalidate(resultPublicId); - } - - // TODO Should we use "gzip" instead? - CompressionType compression = (compressionEnabled_ ? CompressionType_ZlibWithSize : CompressionType_None); - - FileInfo dicomInfo = accessor.Write(dicom.GetBufferData(), dicom.GetBufferSize(), - FileContentType_Dicom, compression, storeMD5_); - FileInfo jsonInfo = accessor.Write(dicom.GetJson().toStyledString(), - FileContentType_DicomAsJson, compression, storeMD5_); - - ServerIndex::Attachments attachments; - attachments.push_back(dicomInfo); - attachments.push_back(jsonInfo); - - typedef std::map InstanceMetadata; - InstanceMetadata instanceMetadata; - StoreStatus status = index_.Store( - instanceMetadata, dicom, attachments, overwrite); - - // Only keep the metadata for the "instance" level - dicom.GetMetadata().clear(); - - for (InstanceMetadata::const_iterator it = instanceMetadata.begin(); - it != instanceMetadata.end(); ++it) - { - dicom.GetMetadata().insert(std::make_pair(std::make_pair(ResourceType_Instance, it->first), - it->second)); - } - - if (status != StoreStatus_Success) - { - accessor.Remove(dicomInfo); - accessor.Remove(jsonInfo); - } - - switch (status) - { - case StoreStatus_Success: - LOG(INFO) << "New instance stored"; - break; - - case StoreStatus_AlreadyStored: - LOG(INFO) << "Already stored"; - break; - - case StoreStatus_Failure: - LOG(ERROR) << "Store failure"; - break; - - default: - // This should never happen - break; - } - - if (status == StoreStatus_Success || - status == StoreStatus_AlreadyStored) - { - boost::shared_lock lock(listenersMutex_); - - for (ServerListeners::iterator it = listeners_.begin(); it != listeners_.end(); ++it) - { - try - { - it->GetListener().SignalStoredInstance(resultPublicId, dicom, simplifiedTags); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Error in the " << it->GetDescription() - << " callback while receiving an instance: " << e.What() - << " (code " << e.GetErrorCode() << ")"; - } - } - } - - return status; - } - catch (OrthancException& e) - { - if (e.GetErrorCode() == ErrorCode_InexistentTag) - { - dicom.GetSummary().LogMissingTagsForStore(); - } - - throw; - } - } - - - StoreStatus ServerContext::Store(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode) - { - if (!isIngestTranscoding_) - { - // No automated transcoding. This was the only path in Orthanc <= 1.6.1. - return StoreAfterTranscoding(resultPublicId, dicom, mode); - } - else - { - // Automated transcoding of incoming DICOM files - - DicomTransferSyntax sourceSyntax; - if (!FromDcmtkBridge::LookupOrthancTransferSyntax( - sourceSyntax, dicom.GetParsedDicomFile().GetDcmtkObject()) || - sourceSyntax == ingestTransferSyntax_) - { - // No transcoding - return StoreAfterTranscoding(resultPublicId, dicom, mode); - } - else - { - std::set syntaxes; - syntaxes.insert(ingestTransferSyntax_); - - IDicomTranscoder::DicomImage source; - source.SetExternalBuffer(dicom.GetBufferData(), dicom.GetBufferSize()); - - IDicomTranscoder::DicomImage transcoded; - if (Transcode(transcoded, source, syntaxes, true /* allow new SOP instance UID */)) - { - std::unique_ptr tmp(transcoded.ReleaseAsParsedDicomFile()); - - DicomInstanceToStore toStore; - toStore.SetParsedDicomFile(*tmp); - toStore.SetOrigin(dicom.GetOrigin()); - - StoreStatus ok = StoreAfterTranscoding(resultPublicId, toStore, mode); - assert(resultPublicId == tmp->GetHasher().HashInstance()); - - return ok; - } - else - { - // Cannot transcode => store the original file - return StoreAfterTranscoding(resultPublicId, dicom, mode); - } - } - } - } - - - void ServerContext::AnswerAttachment(RestApiOutput& output, - const std::string& resourceId, - FileContentType content) - { - FileInfo attachment; - if (!index_.LookupAttachment(attachment, resourceId, content)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - StorageAccessor accessor(area_, GetMetricsRegistry()); - accessor.AnswerFile(output, attachment, GetFileContentMime(content)); - } - - - void ServerContext::ChangeAttachmentCompression(const std::string& resourceId, - FileContentType attachmentType, - CompressionType compression) - { - LOG(INFO) << "Changing compression type for attachment " - << EnumerationToString(attachmentType) - << " of resource " << resourceId << " to " - << compression; - - FileInfo attachment; - if (!index_.LookupAttachment(attachment, resourceId, attachmentType)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - if (attachment.GetCompressionType() == compression) - { - // Nothing to do - return; - } - - std::string content; - - StorageAccessor accessor(area_, GetMetricsRegistry()); - accessor.Read(content, attachment); - - FileInfo modified = accessor.Write(content.empty() ? NULL : content.c_str(), - content.size(), attachmentType, compression, storeMD5_); - - try - { - StoreStatus status = index_.AddAttachment(modified, resourceId); - if (status != StoreStatus_Success) - { - accessor.Remove(modified); - throw OrthancException(ErrorCode_Database); - } - } - catch (OrthancException&) - { - accessor.Remove(modified); - throw; - } - } - - - void ServerContext::ReadDicomAsJsonInternal(std::string& result, - const std::string& instancePublicId) - { - FileInfo attachment; - if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson)) - { - ReadAttachment(result, attachment); - } - else - { - // The "DICOM as JSON" summary is not available from the Orthanc - // store (most probably deleted), reconstruct it from the DICOM file - std::string dicom; - ReadDicom(dicom, instancePublicId); - - LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: " - << instancePublicId; - - ParsedDicomFile parsed(dicom); - - Json::Value summary; - parsed.DatasetToJson(summary); - - result = summary.toStyledString(); - - if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson, - result.c_str(), result.size())) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot associate the DICOM-as-JSON summary to instance: " + instancePublicId); - } - } - } - - - void ServerContext::ReadDicomAsJson(std::string& result, - const std::string& instancePublicId, - const std::set& ignoreTagLength) - { - if (ignoreTagLength.empty()) - { - ReadDicomAsJsonInternal(result, instancePublicId); - } - else - { - Json::Value tmp; - ReadDicomAsJson(tmp, instancePublicId, ignoreTagLength); - result = tmp.toStyledString(); - } - } - - - void ServerContext::ReadDicomAsJson(Json::Value& result, - const std::string& instancePublicId, - const std::set& ignoreTagLength) - { - if (ignoreTagLength.empty()) - { - std::string tmp; - ReadDicomAsJsonInternal(tmp, instancePublicId); - - Json::Reader reader; - if (!reader.parse(tmp, result)) - { - throw OrthancException(ErrorCode_CorruptedFile); - } - } - else - { - // The "DicomAsJson" attachment might have stored some tags as - // "too long". We are forced to re-parse the DICOM file. - std::string dicom; - ReadDicom(dicom, instancePublicId); - - ParsedDicomFile parsed(dicom); - parsed.DatasetToJson(result, ignoreTagLength); - } - } - - - void ServerContext::ReadAttachment(std::string& result, - const std::string& instancePublicId, - FileContentType content, - bool uncompressIfNeeded) - { - FileInfo attachment; - if (!index_.LookupAttachment(attachment, instancePublicId, content)) - { - throw OrthancException(ErrorCode_InternalError, - "Unable to read attachment " + EnumerationToString(content) + - " of instance " + instancePublicId); - } - - assert(attachment.GetContentType() == content); - - if (uncompressIfNeeded) - { - ReadAttachment(result, attachment); - } - else - { - // Do not uncompress the content of the storage area, return the - // raw data - StorageAccessor accessor(area_, GetMetricsRegistry()); - accessor.ReadRaw(result, attachment); - } - } - - - void ServerContext::ReadAttachment(std::string& result, - const FileInfo& attachment) - { - // This will decompress the attachment - StorageAccessor accessor(area_, GetMetricsRegistry()); - accessor.Read(result, attachment); - } - - - IDynamicObject* ServerContext::DicomCacheProvider::Provide(const std::string& instancePublicId) - { - std::string content; - context_.ReadDicom(content, instancePublicId); - return new ParsedDicomFile(content); - } - - - ServerContext::DicomCacheLocker::DicomCacheLocker(ServerContext& that, - const std::string& instancePublicId) : - that_(that), - lock_(that_.dicomCacheMutex_) - { -#if ENABLE_DICOM_CACHE == 0 - static std::unique_ptr p; - p.reset(that_.provider_.Provide(instancePublicId)); - dicom_ = dynamic_cast(p.get()); -#else - dicom_ = &dynamic_cast(that_.dicomCache_.Access(instancePublicId)); -#endif - } - - - ServerContext::DicomCacheLocker::~DicomCacheLocker() - { - } - - - void ServerContext::SetStoreMD5ForAttachments(bool storeMD5) - { - LOG(INFO) << "Storing MD5 for attachments: " << (storeMD5 ? "yes" : "no"); - storeMD5_ = storeMD5; - } - - - bool ServerContext::AddAttachment(const std::string& resourceId, - FileContentType attachmentType, - const void* data, - size_t size) - { - LOG(INFO) << "Adding attachment " << EnumerationToString(attachmentType) << " to resource " << resourceId; - - // TODO Should we use "gzip" instead? - CompressionType compression = (compressionEnabled_ ? CompressionType_ZlibWithSize : CompressionType_None); - - StorageAccessor accessor(area_, GetMetricsRegistry()); - FileInfo attachment = accessor.Write(data, size, attachmentType, compression, storeMD5_); - - StoreStatus status = index_.AddAttachment(attachment, resourceId); - if (status != StoreStatus_Success) - { - accessor.Remove(attachment); - return false; - } - else - { - return true; - } - } - - - bool ServerContext::DeleteResource(Json::Value& target, - const std::string& uuid, - ResourceType expectedType) - { - if (expectedType == ResourceType_Instance) - { - // remove the file from the DicomCache - boost::mutex::scoped_lock lock(dicomCacheMutex_); - dicomCache_.Invalidate(uuid); - } - - return index_.DeleteResource(target, uuid, expectedType); - } - - - void ServerContext::SignalChange(const ServerIndexChange& change) - { - pendingChanges_.Enqueue(change.Clone()); - } - - -#if ORTHANC_ENABLE_PLUGINS == 1 - void ServerContext::SetPlugins(OrthancPlugins& plugins) - { - boost::unique_lock lock(listenersMutex_); - - plugins_ = &plugins; - - // TODO REFACTOR THIS - listeners_.clear(); - listeners_.push_back(ServerListener(luaListener_, "Lua")); - listeners_.push_back(ServerListener(plugins, "plugin")); - } - - - void ServerContext::ResetPlugins() - { - boost::unique_lock lock(listenersMutex_); - - plugins_ = NULL; - - // TODO REFACTOR THIS - listeners_.clear(); - listeners_.push_back(ServerListener(luaListener_, "Lua")); - } - - - const OrthancPlugins& ServerContext::GetPlugins() const - { - if (HasPlugins()) - { - return *plugins_; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - - OrthancPlugins& ServerContext::GetPlugins() - { - if (HasPlugins()) - { - return *plugins_; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - -#endif - - - bool ServerContext::HasPlugins() const - { -#if ORTHANC_ENABLE_PLUGINS == 1 - return (plugins_ != NULL); -#else - return false; -#endif - } - - - void ServerContext::Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - size_t since, - size_t limit) - { - unsigned int databaseLimit = (queryLevel == ResourceType_Instance ? - limitFindInstances_ : limitFindResults_); - - std::vector resources, instances; - - { - const size_t lookupLimit = (databaseLimit == 0 ? 0 : databaseLimit + 1); - GetIndex().ApplyLookupResources(resources, &instances, lookup, queryLevel, lookupLimit); - } - - bool complete = (databaseLimit == 0 || - resources.size() <= databaseLimit); - - LOG(INFO) << "Number of candidate resources after fast DB filtering on main DICOM tags: " << resources.size(); - - /** - * "resources" contains the Orthanc ID of the resource at level - * "queryLevel", "instances" contains one the Orthanc ID of one - * sample instance from this resource. - **/ - assert(resources.size() == instances.size()); - - size_t countResults = 0; - size_t skipped = 0; - - const bool isDicomAsJsonNeeded = visitor.IsDicomAsJsonNeeded(); - - for (size_t i = 0; i < instances.size(); i++) - { - // Optimization in Orthanc 1.5.1 - Don't read the full JSON from - // the disk if only "main DICOM tags" are to be returned - - std::unique_ptr dicomAsJson; - - bool hasOnlyMainDicomTags; - DicomMap dicom; - - if (findStorageAccessMode_ == FindStorageAccessMode_DatabaseOnly || - findStorageAccessMode_ == FindStorageAccessMode_DiskOnAnswer || - lookup.HasOnlyMainDicomTags()) - { - // Case (1): The main DICOM tags, as stored in the database, - // are sufficient to look for match - - DicomMap tmp; - if (!GetIndex().GetAllMainDicomTags(tmp, instances[i])) - { - // The instance has been removed during the execution of the - // lookup, ignore it - continue; - } - -#if 1 - // New in Orthanc 1.6.0: Only keep the main DICOM tags at the - // level of interest for the query - switch (queryLevel) - { - // WARNING: Don't reorder cases below, and don't add "break" - case ResourceType_Instance: - dicom.MergeMainDicomTags(tmp, ResourceType_Instance); - - case ResourceType_Series: - dicom.MergeMainDicomTags(tmp, ResourceType_Series); - - case ResourceType_Study: - dicom.MergeMainDicomTags(tmp, ResourceType_Study); - - case ResourceType_Patient: - dicom.MergeMainDicomTags(tmp, ResourceType_Patient); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - // Special case of the "Modality" at the study level, in order - // to deal with C-FIND on "ModalitiesInStudy" (0008,0061). - // Check out integration test "test_rest_modalities_in_study". - if (queryLevel == ResourceType_Study) - { - dicom.CopyTagIfExists(tmp, DICOM_TAG_MODALITY); - } -#else - dicom.Assign(tmp); // This emulates Orthanc <= 1.5.8 -#endif - - hasOnlyMainDicomTags = true; - } - else - { - // Case (2): Need to read the "DICOM-as-JSON" attachment from - // the storage area - dicomAsJson.reset(new Json::Value); - ReadDicomAsJson(*dicomAsJson, instances[i]); - - dicom.FromDicomAsJson(*dicomAsJson); - - // This map contains the entire JSON, i.e. more than the main DICOM tags - hasOnlyMainDicomTags = false; - } - - if (lookup.IsMatch(dicom)) - { - if (skipped < since) - { - skipped++; - } - else if (limit != 0 && - countResults >= limit) - { - // Too many results, don't mark as complete - complete = false; - break; - } - else - { - if ((findStorageAccessMode_ == FindStorageAccessMode_DiskOnLookupAndAnswer || - findStorageAccessMode_ == FindStorageAccessMode_DiskOnAnswer) && - dicomAsJson.get() == NULL && - isDicomAsJsonNeeded) - { - dicomAsJson.reset(new Json::Value); - ReadDicomAsJson(*dicomAsJson, instances[i]); - } - - if (hasOnlyMainDicomTags) - { - // This is Case (1): The variable "dicom" only contains the main DICOM tags - visitor.Visit(resources[i], instances[i], dicom, dicomAsJson.get()); - } - else - { - // Remove the non-main DICOM tags from "dicom" if Case (2) - // was used, for consistency with Case (1) - - DicomMap mainDicomTags; - mainDicomTags.ExtractMainDicomTags(dicom); - visitor.Visit(resources[i], instances[i], mainDicomTags, dicomAsJson.get()); - } - - countResults ++; - } - } - } - - if (complete) - { - visitor.MarkAsComplete(); - } - - LOG(INFO) << "Number of matching resources: " << countResults; - } - - - bool ServerContext::LookupOrReconstructMetadata(std::string& target, - const std::string& publicId, - MetadataType metadata) - { - // This is a backwards-compatibility function, that can - // reconstruct metadata that were not generated by an older - // release of Orthanc - - if (metadata == MetadataType_Instance_SopClassUid || - metadata == MetadataType_Instance_TransferSyntax) - { - if (index_.LookupMetadata(target, publicId, metadata)) - { - return true; - } - else - { - // These metadata are mandatory in DICOM instances, and were - // introduced in Orthanc 1.2.0. The fact that - // "LookupMetadata()" has failed indicates that this database - // comes from an older release of Orthanc. - - DicomTag tag(0, 0); - - switch (metadata) - { - case MetadataType_Instance_SopClassUid: - tag = DICOM_TAG_SOP_CLASS_UID; - break; - - case MetadataType_Instance_TransferSyntax: - tag = DICOM_TAG_TRANSFER_SYNTAX_UID; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - Json::Value dicomAsJson; - ReadDicomAsJson(dicomAsJson, publicId); - - DicomMap tags; - tags.FromDicomAsJson(dicomAsJson); - - const DicomValue* value = tags.TestAndGetValue(tag); - - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - target = value->GetContent(); - - // Store for reuse - index_.SetMetadata(publicId, metadata, target); - return true; - } - else - { - // Should never happen - return false; - } - } - } - else - { - // No backward - return index_.LookupMetadata(target, publicId, metadata); - } - } - - - void ServerContext::AddChildInstances(SetOfInstancesJob& job, - const std::string& publicId) - { - std::list instances; - GetIndex().GetChildInstances(instances, publicId); - - job.Reserve(job.GetInstancesCount() + instances.size()); - - for (std::list::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - job.AddInstance(*it); - } - } - - - void ServerContext::SignalUpdatedModalities() - { -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins()) - { - GetPlugins().SignalUpdatedModalities(); - } -#endif - } - - - void ServerContext::SignalUpdatedPeers() - { -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins()) - { - GetPlugins().SignalUpdatedPeers(); - } -#endif - } - - - IStorageCommitmentFactory::ILookupHandler* - ServerContext::CreateStorageCommitment(const std::string& jobId, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::string& remoteAet, - const std::string& calledAet) - { -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins()) - { - return GetPlugins().CreateStorageCommitment( - jobId, transactionUid, sopClassUids, sopInstanceUids, remoteAet, calledAet); - } -#endif - - return NULL; - } - - - ImageAccessor* ServerContext::DecodeDicomFrame(const std::string& publicId, - unsigned int frameIndex) - { - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) - { - // Use Orthanc's built-in decoder, using the cache to speed-up - // things on multi-frame images - ServerContext::DicomCacheLocker locker(*this, publicId); - std::unique_ptr decoded( - DicomImageDecoder::Decode(locker.GetDicom(), frameIndex)); - if (decoded.get() != NULL) - { - return decoded.release(); - } - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins() && - GetPlugins().HasCustomImageDecoder()) - { - // TODO: Store the raw buffer in the DicomCacheLocker - std::string dicomContent; - ReadDicom(dicomContent, publicId); - std::unique_ptr decoded( - GetPlugins().Decode(dicomContent.c_str(), dicomContent.size(), frameIndex)); - if (decoded.get() != NULL) - { - return decoded.release(); - } - else if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - LOG(INFO) << "The installed image decoding plugins cannot handle an image, " - << "fallback to the built-in DCMTK decoder"; - } - } -#endif - - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - ServerContext::DicomCacheLocker locker(*this, publicId); - return DicomImageDecoder::Decode(locker.GetDicom(), frameIndex); - } - else - { - return NULL; // Built-in decoder is disabled - } - } - - - ImageAccessor* ServerContext::DecodeDicomFrame(const DicomInstanceToStore& dicom, - unsigned int frameIndex) - { - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) - { - std::unique_ptr decoded( - DicomImageDecoder::Decode(dicom.GetParsedDicomFile(), frameIndex)); - if (decoded.get() != NULL) - { - return decoded.release(); - } - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins() && - GetPlugins().HasCustomImageDecoder()) - { - std::unique_ptr decoded( - GetPlugins().Decode(dicom.GetBufferData(), dicom.GetBufferSize(), frameIndex)); - if (decoded.get() != NULL) - { - return decoded.release(); - } - else if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - LOG(INFO) << "The installed image decoding plugins cannot handle an image, " - << "fallback to the built-in DCMTK decoder"; - } - } -#endif - - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - return DicomImageDecoder::Decode(dicom.GetParsedDicomFile(), frameIndex); - } - else - { - return NULL; - } - } - - - void ServerContext::StoreWithTranscoding(std::string& sopClassUid, - std::string& sopInstanceUid, - DicomStoreUserConnection& connection, - const std::string& dicom, - bool hasMoveOriginator, - const std::string& moveOriginatorAet, - uint16_t moveOriginatorId) - { - const void* data = dicom.empty() ? NULL : dicom.c_str(); - - if (!transcodeDicomProtocol_ || - !connection.GetParameters().GetRemoteModality().IsTranscodingAllowed()) - { - connection.Store(sopClassUid, sopInstanceUid, data, dicom.size(), - hasMoveOriginator, moveOriginatorAet, moveOriginatorId); - } - else - { - connection.Transcode(sopClassUid, sopInstanceUid, *this, data, dicom.size(), - hasMoveOriginator, moveOriginatorAet, moveOriginatorId); - } - } - - - bool ServerContext::Transcode(DicomImage& target, - DicomImage& source /* in, "GetParsed()" possibly modified */, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) - { - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) - { - if (dcmtkTranscoder_->Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid)) - { - return true; - } - } - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (HasPlugins() && - GetPlugins().HasCustomTranscoder()) - { - if (GetPlugins().Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid)) - { - return true; - } - else if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - LOG(INFO) << "The installed transcoding plugins cannot handle an image, " - << "fallback to the built-in DCMTK transcoder"; - } - } -#endif - - if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) - { - return dcmtkTranscoder_->Transcode(target, source, allowedSyntaxes, allowNewSopInstanceUid); - } - else - { - return false; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerContext.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,492 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "IServerListener.h" -#include "LuaScripting.h" -#include "OrthancHttpHandler.h" -#include "ServerIndex.h" -#include "ServerJobs/IStorageCommitmentFactory.h" - -#include "../Core/Cache/MemoryCache.h" -#include "../Core/DicomParsing/IDicomTranscoder.h" - - -namespace Orthanc -{ - class DicomInstanceToStore; - class IStorageArea; - class JobsEngine; - class MetricsRegistry; - class OrthancPlugins; - class ParsedDicomFile; - class RestApiOutput; - class SetOfInstancesJob; - class SharedArchive; - class SharedMessageQueue; - class StorageCommitmentReports; - - - /** - * This class is responsible for maintaining the storage area on the - * filesystem (including compression), as well as the index of the - * DICOM store. It implements the required locking mechanisms. - **/ - class ServerContext : - public IStorageCommitmentFactory, - public IDicomTranscoder, - private JobsRegistry::IObserver - { - public: - class ILookupVisitor : public boost::noncopyable - { - public: - virtual ~ILookupVisitor() - { - } - - virtual bool IsDicomAsJsonNeeded() const = 0; - - virtual void MarkAsComplete() = 0; - - virtual void Visit(const std::string& publicId, - const std::string& instanceId, - const DicomMap& mainDicomTags, - const Json::Value* dicomAsJson) = 0; - }; - - - private: - class LuaServerListener : public IServerListener - { - private: - ServerContext& context_; - - public: - LuaServerListener(ServerContext& context) : - context_(context) - { - } - - virtual void SignalStoredInstance(const std::string& publicId, - const DicomInstanceToStore& instance, - const Json::Value& simplifiedTags) - { - context_.mainLua_.SignalStoredInstance(publicId, instance, simplifiedTags); - } - - virtual void SignalChange(const ServerIndexChange& change) - { - context_.mainLua_.SignalChange(change); - } - - virtual bool FilterIncomingInstance(const DicomInstanceToStore& instance, - const Json::Value& simplified) - { - return context_.filterLua_.FilterIncomingInstance(instance, simplified); - } - }; - - class DicomCacheProvider : public Deprecated::ICachePageProvider // TODO - { - private: - ServerContext& context_; - - public: - DicomCacheProvider(ServerContext& context) : context_(context) - { - } - - virtual IDynamicObject* Provide(const std::string& id); - }; - - class ServerListener - { - private: - IServerListener *listener_; - std::string description_; - - public: - ServerListener(IServerListener& listener, - const std::string& description) : - listener_(&listener), - description_(description) - { - } - - IServerListener& GetListener() - { - return *listener_; - } - - const std::string& GetDescription() - { - return description_; - } - }; - - typedef std::list ServerListeners; - - - static void ChangeThread(ServerContext* that, - unsigned int sleepDelay); - - static void SaveJobsThread(ServerContext* that, - unsigned int sleepDelay); - - void ReadDicomAsJsonInternal(std::string& result, - const std::string& instancePublicId); - - void SaveJobsEngine(); - - virtual void SignalJobSubmitted(const std::string& jobId) ORTHANC_OVERRIDE; - - virtual void SignalJobSuccess(const std::string& jobId) ORTHANC_OVERRIDE; - - virtual void SignalJobFailure(const std::string& jobId) ORTHANC_OVERRIDE; - - ServerIndex index_; - IStorageArea& area_; - - bool compressionEnabled_; - bool storeMD5_; - - DicomCacheProvider provider_; - boost::mutex dicomCacheMutex_; - Deprecated::MemoryCache dicomCache_; // TODO - - LuaScripting mainLua_; - LuaScripting filterLua_; - LuaServerListener luaListener_; - std::unique_ptr mediaArchive_; - - // The "JobsEngine" must be *after* "LuaScripting", as - // "LuaScripting" embeds "LuaJobManager" that registers as an - // observer to "SequenceOfOperationsJob", whose lifetime - // corresponds to that of "JobsEngine". It must also be after - // "mediaArchive_", as jobs might access this archive. - JobsEngine jobsEngine_; - -#if ORTHANC_ENABLE_PLUGINS == 1 - OrthancPlugins* plugins_; -#endif - - ServerListeners listeners_; - boost::shared_mutex listenersMutex_; - - bool done_; - bool haveJobsChanged_; - bool isJobsEngineUnserialized_; - SharedMessageQueue pendingChanges_; - boost::thread changeThread_; - boost::thread saveJobsThread_; - - std::unique_ptr queryRetrieveArchive_; - std::string defaultLocalAet_; - OrthancHttpHandler httpHandler_; - bool saveJobs_; - FindStorageAccessMode findStorageAccessMode_; - unsigned int limitFindInstances_; - unsigned int limitFindResults_; - - std::unique_ptr metricsRegistry_; - bool isHttpServerSecure_; - bool isExecuteLuaEnabled_; - bool overwriteInstances_; - - std::unique_ptr storageCommitmentReports_; - - bool transcodeDicomProtocol_; - std::unique_ptr dcmtkTranscoder_; - BuiltinDecoderTranscoderOrder builtinDecoderTranscoderOrder_; - bool isIngestTranscoding_; - DicomTransferSyntax ingestTransferSyntax_; - - StoreStatus StoreAfterTranscoding(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode); - - public: - class DicomCacheLocker : public boost::noncopyable - { - private: - ServerContext& that_; - ParsedDicomFile *dicom_; - boost::mutex::scoped_lock lock_; - - public: - DicomCacheLocker(ServerContext& that, - const std::string& instancePublicId); - - ~DicomCacheLocker(); - - ParsedDicomFile& GetDicom() - { - return *dicom_; - } - }; - - ServerContext(IDatabaseWrapper& database, - IStorageArea& area, - bool unitTesting, - size_t maxCompletedJobs); - - ~ServerContext(); - - void SetupJobsEngine(bool unitTesting, - bool loadJobsFromDatabase); - - ServerIndex& GetIndex() - { - return index_; - } - - void SetCompressionEnabled(bool enabled); - - bool IsCompressionEnabled() const - { - return compressionEnabled_; - } - - void RemoveFile(const std::string& fileUuid, - FileContentType type); - - bool AddAttachment(const std::string& resourceId, - FileContentType attachmentType, - const void* data, - size_t size); - - StoreStatus Store(std::string& resultPublicId, - DicomInstanceToStore& dicom, - StoreInstanceMode mode); - - void AnswerAttachment(RestApiOutput& output, - const std::string& resourceId, - FileContentType content); - - void ChangeAttachmentCompression(const std::string& resourceId, - FileContentType attachmentType, - CompressionType compression); - - void ReadDicomAsJson(std::string& result, - const std::string& instancePublicId, - const std::set& ignoreTagLength); - - void ReadDicomAsJson(Json::Value& result, - const std::string& instancePublicId, - const std::set& ignoreTagLength); - - void ReadDicomAsJson(std::string& result, - const std::string& instancePublicId) - { - std::set ignoreTagLength; - ReadDicomAsJson(result, instancePublicId, ignoreTagLength); - } - - void ReadDicomAsJson(Json::Value& result, - const std::string& instancePublicId) - { - std::set ignoreTagLength; - ReadDicomAsJson(result, instancePublicId, ignoreTagLength); - } - - void ReadDicom(std::string& dicom, - const std::string& instancePublicId) - { - ReadAttachment(dicom, instancePublicId, FileContentType_Dicom, true); - } - - // TODO CACHING MECHANISM AT THIS POINT - void ReadAttachment(std::string& result, - const std::string& instancePublicId, - FileContentType content, - bool uncompressIfNeeded); - - void ReadAttachment(std::string& result, - const FileInfo& attachment); - - void SetStoreMD5ForAttachments(bool storeMD5); - - bool IsStoreMD5ForAttachments() const - { - return storeMD5_; - } - - JobsEngine& GetJobsEngine() - { - return jobsEngine_; - } - - bool DeleteResource(Json::Value& target, - const std::string& uuid, - ResourceType expectedType); - - void SignalChange(const ServerIndexChange& change); - - SharedArchive& GetQueryRetrieveArchive() - { - return *queryRetrieveArchive_; - } - - SharedArchive& GetMediaArchive() - { - return *mediaArchive_; - } - - const std::string& GetDefaultLocalApplicationEntityTitle() const - { - return defaultLocalAet_; - } - - LuaScripting& GetLuaScripting() - { - return mainLua_; - } - - OrthancHttpHandler& GetHttpHandler() - { - return httpHandler_; - } - - void Stop(); - - void Apply(ILookupVisitor& visitor, - const DatabaseLookup& lookup, - ResourceType queryLevel, - size_t since, - size_t limit); - - bool LookupOrReconstructMetadata(std::string& target, - const std::string& publicId, - MetadataType type); - - - /** - * Management of the plugins - **/ - -#if ORTHANC_ENABLE_PLUGINS == 1 - void SetPlugins(OrthancPlugins& plugins); - - void ResetPlugins(); - - const OrthancPlugins& GetPlugins() const; - - OrthancPlugins& GetPlugins(); -#endif - - bool HasPlugins() const; - - void AddChildInstances(SetOfInstancesJob& job, - const std::string& publicId); - - void SignalUpdatedModalities(); - - void SignalUpdatedPeers(); - - MetricsRegistry& GetMetricsRegistry() - { - return *metricsRegistry_; - } - - void SetHttpServerSecure(bool isSecure) - { - isHttpServerSecure_ = isSecure; - } - - bool IsHttpServerSecure() const - { - return isHttpServerSecure_; - } - - void SetExecuteLuaEnabled(bool enabled) - { - isExecuteLuaEnabled_ = enabled; - } - - bool IsExecuteLuaEnabled() const - { - return isExecuteLuaEnabled_; - } - - void SetOverwriteInstances(bool overwrite) - { - overwriteInstances_ = overwrite; - } - - bool IsOverwriteInstances() const - { - return overwriteInstances_; - } - - virtual IStorageCommitmentFactory::ILookupHandler* - CreateStorageCommitment(const std::string& jobId, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::string& remoteAet, - const std::string& calledAet) ORTHANC_OVERRIDE; - - StorageCommitmentReports& GetStorageCommitmentReports() - { - return *storageCommitmentReports_; - } - - ImageAccessor* DecodeDicomFrame(const std::string& publicId, - unsigned int frameIndex); - - ImageAccessor* DecodeDicomFrame(const DicomInstanceToStore& dicom, - unsigned int frameIndex); - - void StoreWithTranscoding(std::string& sopClassUid, - std::string& sopInstanceUid, - DicomStoreUserConnection& connection, - const std::string& dicom, - bool hasMoveOriginator, - const std::string& moveOriginatorAet, - uint16_t moveOriginatorId); - - // This method can be used even if the global option - // "TranscodeDicomProtocol" is set to "false" - virtual bool Transcode(DicomImage& target, - DicomImage& source /* in, "GetParsed()" possibly modified */, - const std::set& allowedSyntaxes, - bool allowNewSopInstanceUid) ORTHANC_OVERRIDE; - - bool IsTranscodeDicomProtocol() const - { - return transcodeDicomProtocol_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,376 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "ServerEnumerations.h" - -#include "../Core/OrthancException.h" -#include "../Core/EnumerationDictionary.h" -#include "../Core/Logging.h" -#include "../Core/Toolbox.h" - -#include - -namespace Orthanc -{ - typedef std::map MimeTypes; - - static boost::mutex enumerationsMutex_; - static Toolbox::EnumerationDictionary dictMetadataType_; - static Toolbox::EnumerationDictionary dictContentType_; - static MimeTypes mimeTypes_; - - void InitializeServerEnumerations() - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - dictMetadataType_.Clear(); - dictContentType_.Clear(); - - dictMetadataType_.Add(MetadataType_Instance_IndexInSeries, "IndexInSeries"); - dictMetadataType_.Add(MetadataType_Instance_ReceptionDate, "ReceptionDate"); - dictMetadataType_.Add(MetadataType_Instance_RemoteAet, "RemoteAET"); - dictMetadataType_.Add(MetadataType_Series_ExpectedNumberOfInstances, "ExpectedNumberOfInstances"); - dictMetadataType_.Add(MetadataType_ModifiedFrom, "ModifiedFrom"); - dictMetadataType_.Add(MetadataType_AnonymizedFrom, "AnonymizedFrom"); - dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate"); - dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin"); - dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax"); - dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid"); - dictMetadataType_.Add(MetadataType_Instance_RemoteIp, "RemoteIP"); - dictMetadataType_.Add(MetadataType_Instance_CalledAet, "CalledAET"); - dictMetadataType_.Add(MetadataType_Instance_HttpUsername, "HttpUsername"); - - dictContentType_.Add(FileContentType_Dicom, "dicom"); - dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json"); - } - - void RegisterUserMetadata(int metadata, - const std::string& name) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - MetadataType type = static_cast(metadata); - - if (metadata < 0 || - !IsUserMetadata(type)) - { - LOG(ERROR) << "A user content type must have index between " - << static_cast(MetadataType_StartUser) << " and " - << static_cast(MetadataType_EndUser) << ", but \"" - << name << "\" has index " << metadata; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (dictMetadataType_.Contains(type)) - { - LOG(ERROR) << "Cannot associate user content type \"" - << name << "\" with index " << metadata - << ", as this index is already used"; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - dictMetadataType_.Add(type, name); - } - - std::string EnumerationToString(MetadataType type) - { - // This function MUST return a "std::string" and not "const - // char*", as the result is not a static string - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictMetadataType_.Translate(type); - } - - MetadataType StringToMetadata(const std::string& str) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictMetadataType_.Translate(str); - } - - void RegisterUserContentType(int contentType, - const std::string& name, - const std::string& mime) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - FileContentType type = static_cast(contentType); - - if (contentType < 0 || - !IsUserContentType(type)) - { - LOG(ERROR) << "A user content type must have index between " - << static_cast(FileContentType_StartUser) << " and " - << static_cast(FileContentType_EndUser) << ", but \"" - << name << "\" has index " << contentType; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (dictContentType_.Contains(type)) - { - LOG(ERROR) << "Cannot associate user content type \"" - << name << "\" with index " << contentType - << ", as this index is already used"; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - dictContentType_.Add(type, name); - mimeTypes_[type] = mime; - } - - std::string EnumerationToString(FileContentType type) - { - // This function MUST return a "std::string" and not "const - // char*", as the result is not a static string - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictContentType_.Translate(type); - } - - std::string GetFileContentMime(FileContentType type) - { - if (type >= FileContentType_StartUser && - type <= FileContentType_EndUser) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - MimeTypes::const_iterator it = mimeTypes_.find(type); - if (it != mimeTypes_.end()) - { - return it->second; - } - } - - switch (type) - { - case FileContentType_Dicom: - return EnumerationToString(MimeType_Dicom); - - case FileContentType_DicomAsJson: - return MIME_JSON_UTF8; - - default: - return EnumerationToString(MimeType_Binary); - } - } - - FileContentType StringToContentType(const std::string& str) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictContentType_.Translate(str); - } - - - FindStorageAccessMode StringToFindStorageAccessMode(const std::string& value) - { - if (value == "Always") - { - return FindStorageAccessMode_DiskOnLookupAndAnswer; - } - else if (value == "Never") - { - return FindStorageAccessMode_DatabaseOnly; - } - else if (value == "Answers") - { - return FindStorageAccessMode_DiskOnAnswer; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Configuration option \"StorageAccessOnFind\" " - "should be \"Always\", \"Never\" or \"Answers\": " + value); - } - } - - - BuiltinDecoderTranscoderOrder StringToBuiltinDecoderTranscoderOrder(const std::string& value) - { - if (value == "Before") - { - return BuiltinDecoderTranscoderOrder_Before; - } - else if (value == "After") - { - return BuiltinDecoderTranscoderOrder_After; - } - else if (value == "Disabled") - { - return BuiltinDecoderTranscoderOrder_Disabled; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Configuration option \"BuiltinDecoderTranscoderOrder\" " - "should be \"After\", \"Before\" or \"Disabled\": " + value); - } - } - - - std::string GetBasePath(ResourceType type, - const std::string& publicId) - { - switch (type) - { - case ResourceType_Patient: - return "/patients/" + publicId; - - case ResourceType_Study: - return "/studies/" + publicId; - - case ResourceType_Series: - return "/series/" + publicId; - - case ResourceType_Instance: - return "/instances/" + publicId; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - const char* EnumerationToString(SeriesStatus status) - { - switch (status) - { - case SeriesStatus_Complete: - return "Complete"; - - case SeriesStatus_Missing: - return "Missing"; - - case SeriesStatus_Inconsistent: - return "Inconsistent"; - - case SeriesStatus_Unknown: - return "Unknown"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - const char* EnumerationToString(StoreStatus status) - { - switch (status) - { - case StoreStatus_Success: - return "Success"; - - case StoreStatus_AlreadyStored: - return "AlreadyStored"; - - case StoreStatus_Failure: - return "Failure"; - - case StoreStatus_FilteredOut: - return "FilteredOut"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ChangeType type) - { - switch (type) - { - case ChangeType_CompletedSeries: - return "CompletedSeries"; - - case ChangeType_NewInstance: - return "NewInstance"; - - case ChangeType_NewPatient: - return "NewPatient"; - - case ChangeType_NewSeries: - return "NewSeries"; - - case ChangeType_NewStudy: - return "NewStudy"; - - case ChangeType_AnonymizedStudy: - return "AnonymizedStudy"; - - case ChangeType_AnonymizedSeries: - return "AnonymizedSeries"; - - case ChangeType_ModifiedStudy: - return "ModifiedStudy"; - - case ChangeType_ModifiedSeries: - return "ModifiedSeries"; - - case ChangeType_AnonymizedPatient: - return "AnonymizedPatient"; - - case ChangeType_ModifiedPatient: - return "ModifiedPatient"; - - case ChangeType_StablePatient: - return "StablePatient"; - - case ChangeType_StableStudy: - return "StableStudy"; - - case ChangeType_StableSeries: - return "StableSeries"; - - case ChangeType_Deleted: - return "Deleted"; - - case ChangeType_NewChildInstance: - return "NewChildInstance"; - - case ChangeType_UpdatedAttachment: - return "UpdatedAttachment"; - - case ChangeType_UpdatedMetadata: - return "UpdatedMetadata"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool IsUserMetadata(MetadataType metadata) - { - return (metadata >= MetadataType_StartUser && - metadata <= MetadataType_EndUser); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerEnumerations.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - -#pragma once - -#include -#include - -#include "../Core/Enumerations.h" -#include "../Core/DicomFormat/DicomTag.h" - -namespace Orthanc -{ - enum SeriesStatus - { - SeriesStatus_Complete, - SeriesStatus_Missing, - SeriesStatus_Inconsistent, - SeriesStatus_Unknown - }; - - enum StoreStatus - { - StoreStatus_Success, - StoreStatus_AlreadyStored, - StoreStatus_Failure, - StoreStatus_FilteredOut // Removed by NewInstanceFilter - }; - - enum DicomTagType - { - DicomTagType_Identifier, // Tag that whose value is stored and indexed in the DB - DicomTagType_Main, // Tag that is stored in the DB (but not indexed) - DicomTagType_Generic // Tag that is only stored in the JSON files - }; - - enum ConstraintType - { - ConstraintType_Equal, - ConstraintType_SmallerOrEqual, - ConstraintType_GreaterOrEqual, - ConstraintType_Wildcard, - ConstraintType_List - }; - - namespace Compatibility - { - enum IdentifierConstraintType - { - IdentifierConstraintType_Equal, - IdentifierConstraintType_SmallerOrEqual, - IdentifierConstraintType_GreaterOrEqual, - IdentifierConstraintType_Wildcard /* Case sensitive, "*" or "?" are the only allowed wildcards */ - }; - } - - enum FindStorageAccessMode - { - FindStorageAccessMode_DatabaseOnly, - FindStorageAccessMode_DiskOnAnswer, - FindStorageAccessMode_DiskOnLookupAndAnswer - }; - - enum StoreInstanceMode - { - StoreInstanceMode_Default, - StoreInstanceMode_OverwriteDuplicate, - StoreInstanceMode_IgnoreDuplicate - }; - - - /** - * WARNING: Do not change the explicit values in the enumerations - * below this point. This would result in incompatible databases - * between versions of Orthanc! - **/ - - enum GlobalProperty - { - GlobalProperty_DatabaseSchemaVersion = 1, // Unused in the Orthanc core as of Orthanc 0.9.5 - GlobalProperty_FlushSleep = 2, - GlobalProperty_AnonymizationSequence = 3, - GlobalProperty_JobsRegistry = 5, - GlobalProperty_GetTotalSizeIsFast = 6, // New in Orthanc 1.5.2 - GlobalProperty_Modalities = 20, // New in Orthanc 1.5.0 - GlobalProperty_Peers = 21, // New in Orthanc 1.5.0 - - // Reserved values for internal use by the database plugins - GlobalProperty_DatabasePatchLevel = 4, - GlobalProperty_DatabaseInternal0 = 10, - GlobalProperty_DatabaseInternal1 = 11, - GlobalProperty_DatabaseInternal2 = 12, - GlobalProperty_DatabaseInternal3 = 13, - GlobalProperty_DatabaseInternal4 = 14, - GlobalProperty_DatabaseInternal5 = 15, - GlobalProperty_DatabaseInternal6 = 16, - GlobalProperty_DatabaseInternal7 = 17, - GlobalProperty_DatabaseInternal8 = 18, - GlobalProperty_DatabaseInternal9 = 19 - }; - - enum MetadataType - { - MetadataType_Instance_IndexInSeries = 1, - MetadataType_Instance_ReceptionDate = 2, - MetadataType_Instance_RemoteAet = 3, - MetadataType_Series_ExpectedNumberOfInstances = 4, - MetadataType_ModifiedFrom = 5, - MetadataType_AnonymizedFrom = 6, - MetadataType_LastUpdate = 7, - MetadataType_Instance_Origin = 8, // New in Orthanc 0.9.5 - MetadataType_Instance_TransferSyntax = 9, // New in Orthanc 1.2.0 - MetadataType_Instance_SopClassUid = 10, // New in Orthanc 1.2.0 - MetadataType_Instance_RemoteIp = 11, // New in Orthanc 1.4.0 - MetadataType_Instance_CalledAet = 12, // New in Orthanc 1.4.0 - MetadataType_Instance_HttpUsername = 13, // New in Orthanc 1.4.0 - - // Make sure that the value "65535" can be stored into this enumeration - MetadataType_StartUser = 1024, - MetadataType_EndUser = 65535 - }; - - enum ChangeType - { - ChangeType_CompletedSeries = 1, - ChangeType_NewInstance = 2, - ChangeType_NewPatient = 3, - ChangeType_NewSeries = 4, - ChangeType_NewStudy = 5, - ChangeType_AnonymizedStudy = 6, - ChangeType_AnonymizedSeries = 7, - ChangeType_ModifiedStudy = 8, - ChangeType_ModifiedSeries = 9, - ChangeType_AnonymizedPatient = 10, - ChangeType_ModifiedPatient = 11, - ChangeType_StablePatient = 12, - ChangeType_StableStudy = 13, - ChangeType_StableSeries = 14, - ChangeType_UpdatedAttachment = 15, - ChangeType_UpdatedMetadata = 16, - - ChangeType_INTERNAL_LastLogged = 4095, - - // The changes below this point are not logged into the database - ChangeType_Deleted = 4096, - ChangeType_NewChildInstance = 4097 - }; - - enum BuiltinDecoderTranscoderOrder - { - BuiltinDecoderTranscoderOrder_Before, - BuiltinDecoderTranscoderOrder_After, - BuiltinDecoderTranscoderOrder_Disabled - }; - - - - void InitializeServerEnumerations(); - - void RegisterUserMetadata(int metadata, - const std::string& name); - - MetadataType StringToMetadata(const std::string& str); - - std::string EnumerationToString(MetadataType type); - - void RegisterUserContentType(int contentType, - const std::string& name, - const std::string& mime); - - FileContentType StringToContentType(const std::string& str); - - FindStorageAccessMode StringToFindStorageAccessMode(const std::string& str); - - BuiltinDecoderTranscoderOrder StringToBuiltinDecoderTranscoderOrder(const std::string& str); - - std::string EnumerationToString(FileContentType type); - - std::string GetFileContentMime(FileContentType type); - - std::string GetBasePath(ResourceType type, - const std::string& publicId); - - const char* EnumerationToString(SeriesStatus status); - - const char* EnumerationToString(StoreStatus status); - - const char* EnumerationToString(ChangeType type); - - bool IsUserMetadata(MetadataType type); -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndexChange.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndexChange.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndexChange.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndexChange.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ServerEnumerations.h" -#include "../Core/IDynamicObject.h" -#include "../Core/SystemToolbox.h" - -#include -#include - -namespace Orthanc -{ - struct ServerIndexChange : public IDynamicObject - { - private: - int64_t seq_; - ChangeType changeType_; - ResourceType resourceType_; - std::string publicId_; - std::string date_; - - public: - ServerIndexChange(ChangeType changeType, - ResourceType resourceType, - const std::string& publicId) : - seq_(-1), - changeType_(changeType), - resourceType_(resourceType), - publicId_(publicId), - date_(SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */)) - { - } - - ServerIndexChange(int64_t seq, - ChangeType changeType, - ResourceType resourceType, - const std::string& publicId, - const std::string& date) : - seq_(seq), - changeType_(changeType), - resourceType_(resourceType), - publicId_(publicId), - date_(date) - { - } - - ServerIndexChange(const ServerIndexChange& other) - : seq_(other.seq_), - changeType_(other.changeType_), - resourceType_(other.resourceType_), - publicId_(other.publicId_), - date_(other.date_) - { - } - - ServerIndexChange* Clone() const - { - return new ServerIndexChange(*this); - } - - int64_t GetSeq() const - { - return seq_; - } - - ChangeType GetChangeType() const - { - return changeType_; - } - - ResourceType GetResourceType() const - { - return resourceType_; - } - - const std::string& GetPublicId() const - { - return publicId_; - } - - const std::string& GetDate() const - { - return date_; - } - - void Format(Json::Value& item) const - { - item = Json::objectValue; - item["Seq"] = static_cast(seq_); - item["ChangeType"] = EnumerationToString(changeType_); - item["ResourceType"] = EnumerationToString(resourceType_); - item["ID"] = publicId_; - item["Path"] = GetBasePath(resourceType_, publicId_); - item["Date"] = date_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,2598 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "ServerIndex.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "../Core/DicomParsing/ParsedDicomFile.h" -#include "../Core/Logging.h" -#include "../Core/Toolbox.h" - -#include "Database/ResourcesContent.h" -#include "DicomInstanceToStore.h" -#include "EmbeddedResources.h" -#include "OrthancConfiguration.h" -#include "Search/DatabaseLookup.h" -#include "Search/DicomTagConstraint.h" -#include "ServerContext.h" -#include "ServerIndexChange.h" -#include "ServerToolbox.h" - -#include -#include - -static const uint64_t MEGA_BYTES = 1024 * 1024; - -namespace Orthanc -{ - static void CopyListToVector(std::vector& target, - const std::list& source) - { - target.resize(source.size()); - - size_t pos = 0; - - for (std::list::const_iterator - it = source.begin(); it != source.end(); ++it) - { - target[pos] = *it; - pos ++; - } - } - - - class ServerIndex::Listener : public IDatabaseListener - { - private: - struct FileToRemove - { - private: - std::string uuid_; - FileContentType type_; - - public: - FileToRemove(const FileInfo& info) : uuid_(info.GetUuid()), - type_(info.GetContentType()) - { - } - - const std::string& GetUuid() const - { - return uuid_; - } - - FileContentType GetContentType() const - { - return type_; - } - }; - - ServerContext& context_; - bool hasRemainingLevel_; - ResourceType remainingType_; - std::string remainingPublicId_; - std::list pendingFilesToRemove_; - std::list pendingChanges_; - uint64_t sizeOfFilesToRemove_; - bool insideTransaction_; - - void Reset() - { - sizeOfFilesToRemove_ = 0; - hasRemainingLevel_ = false; - pendingFilesToRemove_.clear(); - pendingChanges_.clear(); - } - - public: - Listener(ServerContext& context) : context_(context), - insideTransaction_(false) - { - Reset(); - assert(ResourceType_Patient < ResourceType_Study && - ResourceType_Study < ResourceType_Series && - ResourceType_Series < ResourceType_Instance); - } - - void StartTransaction() - { - Reset(); - insideTransaction_ = true; - } - - void EndTransaction() - { - insideTransaction_ = false; - } - - uint64_t GetSizeOfFilesToRemove() - { - return sizeOfFilesToRemove_; - } - - void CommitFilesToRemove() - { - for (std::list::const_iterator - it = pendingFilesToRemove_.begin(); - it != pendingFilesToRemove_.end(); ++it) - { - try - { - context_.RemoveFile(it->GetUuid(), it->GetContentType()); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Unable to remove an attachment from the storage area: " - << it->GetUuid() << " (type: " << EnumerationToString(it->GetContentType()) << ")"; - } - } - } - - void CommitChanges() - { - for (std::list::const_iterator - it = pendingChanges_.begin(); - it != pendingChanges_.end(); ++it) - { - context_.SignalChange(*it); - } - } - - virtual void SignalRemainingAncestor(ResourceType parentType, - const std::string& publicId) - { - VLOG(1) << "Remaining ancestor \"" << publicId << "\" (" << parentType << ")"; - - if (hasRemainingLevel_) - { - if (parentType < remainingType_) - { - remainingType_ = parentType; - remainingPublicId_ = publicId; - } - } - else - { - hasRemainingLevel_ = true; - remainingType_ = parentType; - remainingPublicId_ = publicId; - } - } - - virtual void SignalFileDeleted(const FileInfo& info) - { - assert(Toolbox::IsUuid(info.GetUuid())); - pendingFilesToRemove_.push_back(FileToRemove(info)); - sizeOfFilesToRemove_ += info.GetCompressedSize(); - } - - virtual void SignalChange(const ServerIndexChange& change) - { - VLOG(1) << "Change related to resource " << change.GetPublicId() << " of type " - << EnumerationToString(change.GetResourceType()) << ": " - << EnumerationToString(change.GetChangeType()); - - if (insideTransaction_) - { - pendingChanges_.push_back(change); - } - else - { - context_.SignalChange(change); - } - } - - bool HasRemainingLevel() const - { - return hasRemainingLevel_; - } - - ResourceType GetRemainingType() const - { - assert(HasRemainingLevel()); - return remainingType_; - } - - const std::string& GetRemainingPublicId() const - { - assert(HasRemainingLevel()); - return remainingPublicId_; - } - }; - - - class ServerIndex::Transaction - { - private: - ServerIndex& index_; - std::unique_ptr transaction_; - bool isCommitted_; - - public: - Transaction(ServerIndex& index) : - index_(index), - isCommitted_(false) - { - transaction_.reset(index_.db_.StartTransaction()); - transaction_->Begin(); - - index_.listener_->StartTransaction(); - } - - ~Transaction() - { - index_.listener_->EndTransaction(); - - if (!isCommitted_) - { - transaction_->Rollback(); - } - } - - void Commit(uint64_t sizeOfAddedFiles) - { - if (!isCommitted_) - { - int64_t delta = (static_cast(sizeOfAddedFiles) - - static_cast(index_.listener_->GetSizeOfFilesToRemove())); - - transaction_->Commit(delta); - - // We can remove the files once the SQLite transaction has - // been successfully committed. Some files might have to be - // deleted because of recycling. - index_.listener_->CommitFilesToRemove(); - - // Send all the pending changes to the Orthanc plugins - index_.listener_->CommitChanges(); - - isCommitted_ = true; - } - } - }; - - - class ServerIndex::UnstableResourcePayload - { - private: - ResourceType type_; - std::string publicId_; - boost::posix_time::ptime time_; - - public: - UnstableResourcePayload() : type_(ResourceType_Instance) - { - } - - UnstableResourcePayload(Orthanc::ResourceType type, - const std::string& publicId) : - type_(type), - publicId_(publicId) - { - time_ = boost::posix_time::second_clock::local_time(); - } - - unsigned int GetAge() const - { - return (boost::posix_time::second_clock::local_time() - time_).total_seconds(); - } - - ResourceType GetResourceType() const - { - return type_; - } - - const std::string& GetPublicId() const - { - return publicId_; - } - }; - - - class ServerIndex::MainDicomTagsRegistry : public boost::noncopyable - { - private: - class TagInfo - { - private: - ResourceType level_; - DicomTagType type_; - - public: - TagInfo() - { - } - - TagInfo(ResourceType level, - DicomTagType type) : - level_(level), - type_(type) - { - } - - ResourceType GetLevel() const - { - return level_; - } - - DicomTagType GetType() const - { - return type_; - } - }; - - typedef std::map Registry; - - - Registry registry_; - - void LoadTags(ResourceType level) - { - { - const DicomTag* tags = NULL; - size_t size; - - ServerToolbox::LoadIdentifiers(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (registry_.find(tags[i]) == registry_.end()) - { - registry_[tags[i]] = TagInfo(level, DicomTagType_Identifier); - } - else - { - // These patient-level tags are copied in the study level - assert(level == ResourceType_Study && - (tags[i] == DICOM_TAG_PATIENT_ID || - tags[i] == DICOM_TAG_PATIENT_NAME || - tags[i] == DICOM_TAG_PATIENT_BIRTH_DATE)); - } - } - } - - { - std::set tags; - DicomMap::GetMainDicomTags(tags, level); - - for (std::set::const_iterator - tag = tags.begin(); tag != tags.end(); ++tag) - { - if (registry_.find(*tag) == registry_.end()) - { - registry_[*tag] = TagInfo(level, DicomTagType_Main); - } - } - } - } - - public: - MainDicomTagsRegistry() - { - LoadTags(ResourceType_Patient); - LoadTags(ResourceType_Study); - LoadTags(ResourceType_Series); - LoadTags(ResourceType_Instance); - } - - void LookupTag(ResourceType& level, - DicomTagType& type, - const DicomTag& tag) const - { - Registry::const_iterator it = registry_.find(tag); - - if (it == registry_.end()) - { - // Default values - level = ResourceType_Instance; - type = DicomTagType_Generic; - } - else - { - level = it->second.GetLevel(); - type = it->second.GetType(); - } - } - }; - - - bool ServerIndex::DeleteResource(Json::Value& target, - const std::string& uuid, - ResourceType expectedType) - { - boost::mutex::scoped_lock lock(mutex_); - - Transaction t(*this); - - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, uuid) || - expectedType != type) - { - return false; - } - - db_.DeleteResource(id); - - if (listener_->HasRemainingLevel()) - { - ResourceType type = listener_->GetRemainingType(); - const std::string& uuid = listener_->GetRemainingPublicId(); - - target["RemainingAncestor"] = Json::Value(Json::objectValue); - target["RemainingAncestor"]["Path"] = GetBasePath(type, uuid); - target["RemainingAncestor"]["Type"] = EnumerationToString(type); - target["RemainingAncestor"]["ID"] = uuid; - } - else - { - target["RemainingAncestor"] = Json::nullValue; - } - - t.Commit(0); - - return true; - } - - - void ServerIndex::FlushThread(ServerIndex* that, - unsigned int threadSleep) - { - // By default, wait for 10 seconds before flushing - unsigned int sleep = 10; - - try - { - boost::mutex::scoped_lock lock(that->mutex_); - std::string sleepString; - - if (that->db_.LookupGlobalProperty(sleepString, GlobalProperty_FlushSleep) && - Toolbox::IsInteger(sleepString)) - { - sleep = boost::lexical_cast(sleepString); - } - } - catch (boost::bad_lexical_cast&) - { - } - - LOG(INFO) << "Starting the database flushing thread (sleep = " << sleep << ")"; - - unsigned int count = 0; - - while (!that->done_) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(threadSleep)); - count++; - if (count < sleep) - { - continue; - } - - Logging::Flush(); - - boost::mutex::scoped_lock lock(that->mutex_); - - try - { - that->db_.FlushToDisk(); - } - catch (OrthancException&) - { - LOG(ERROR) << "Cannot flush the SQLite database to the disk (is your filesystem full?)"; - } - - count = 0; - } - - LOG(INFO) << "Stopping the database flushing thread"; - } - - - static bool ComputeExpectedNumberOfInstances(int64_t& target, - const DicomMap& dicomSummary) - { - try - { - const DicomValue* value; - const DicomValue* value2; - - if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGES_IN_ACQUISITION)) != NULL && - !value->IsNull() && - !value->IsBinary() && - (value2 = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS)) != NULL && - !value2->IsNull() && - !value2->IsBinary()) - { - // Patch for series with temporal positions thanks to Will Ryder - int64_t imagesInAcquisition = boost::lexical_cast(value->GetContent()); - int64_t countTemporalPositions = boost::lexical_cast(value2->GetContent()); - target = imagesInAcquisition * countTemporalPositions; - return (target > 0); - } - - else if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_SLICES)) != NULL && - !value->IsNull() && - !value->IsBinary() && - (value2 = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_TIME_SLICES)) != NULL && - !value2->IsBinary() && - !value2->IsNull()) - { - // Support of Cardio-PET images - int64_t numberOfSlices = boost::lexical_cast(value->GetContent()); - int64_t numberOfTimeSlices = boost::lexical_cast(value2->GetContent()); - target = numberOfSlices * numberOfTimeSlices; - return (target > 0); - } - - else if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES)) != NULL && - !value->IsNull() && - !value->IsBinary()) - { - target = boost::lexical_cast(value->GetContent()); - return (target > 0); - } - } - catch (OrthancException&) - { - } - catch (boost::bad_lexical_cast&) - { - } - - return false; - } - - - - - static bool LookupStringMetadata(std::string& result, - const std::map& metadata, - MetadataType type) - { - std::map::const_iterator found = metadata.find(type); - - if (found == metadata.end()) - { - return false; - } - else - { - result = found->second; - return true; - } - } - - - static bool LookupIntegerMetadata(int64_t& result, - const std::map& metadata, - MetadataType type) - { - std::string s; - if (!LookupStringMetadata(s, metadata, type)) - { - return false; - } - - try - { - result = boost::lexical_cast(s); - return true; - } - catch (boost::bad_lexical_cast&) - { - return false; - } - } - - - void ServerIndex::LogChange(int64_t internalId, - ChangeType changeType, - ResourceType resourceType, - const std::string& publicId) - { - ServerIndexChange change(changeType, resourceType, publicId); - - if (changeType <= ChangeType_INTERNAL_LastLogged) - { - db_.LogChange(internalId, change); - } - - assert(listener_.get() != NULL); - listener_->SignalChange(change); - } - - - uint64_t ServerIndex::IncrementGlobalSequenceInternal(GlobalProperty property) - { - std::string oldValue; - - if (db_.LookupGlobalProperty(oldValue, property)) - { - uint64_t oldNumber; - - try - { - oldNumber = boost::lexical_cast(oldValue); - db_.SetGlobalProperty(property, boost::lexical_cast(oldNumber + 1)); - return oldNumber + 1; - } - catch (boost::bad_lexical_cast&) - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - // Initialize the sequence at "1" - db_.SetGlobalProperty(property, "1"); - return 1; - } - } - - - - ServerIndex::ServerIndex(ServerContext& context, - IDatabaseWrapper& db, - unsigned int threadSleep) : - done_(false), - db_(db), - maximumStorageSize_(0), - maximumPatients_(0), - mainDicomTagsRegistry_(new MainDicomTagsRegistry) - { - listener_.reset(new Listener(context)); - db_.SetListener(*listener_); - - // Initial recycling if the parameters have changed since the last - // execution of Orthanc - StandaloneRecycling(); - - if (db.HasFlushToDisk()) - { - flushThread_ = boost::thread(FlushThread, this, threadSleep); - } - - unstableResourcesMonitorThread_ = boost::thread - (UnstableResourcesMonitorThread, this, threadSleep); - } - - - - ServerIndex::~ServerIndex() - { - if (!done_) - { - LOG(ERROR) << "INTERNAL ERROR: ServerIndex::Stop() should be invoked manually to avoid mess in the destruction order!"; - Stop(); - } - } - - - - void ServerIndex::Stop() - { - if (!done_) - { - done_ = true; - - if (db_.HasFlushToDisk() && - flushThread_.joinable()) - { - flushThread_.join(); - } - - if (unstableResourcesMonitorThread_.joinable()) - { - unstableResourcesMonitorThread_.join(); - } - } - } - - - static void SetInstanceMetadata(ResourcesContent& content, - std::map& instanceMetadata, - int64_t instance, - MetadataType metadata, - const std::string& value) - { - content.AddMetadata(instance, metadata, value); - instanceMetadata[metadata] = value; - } - - - void ServerIndex::SignalNewResource(ChangeType changeType, - ResourceType level, - const std::string& publicId, - int64_t internalId) - { - ServerIndexChange change(changeType, level, publicId); - db_.LogChange(internalId, change); - - assert(listener_.get() != NULL); - listener_->SignalChange(change); - } - - - StoreStatus ServerIndex::Store(std::map& instanceMetadata, - DicomInstanceToStore& instanceToStore, - const Attachments& attachments, - bool overwrite) - { - boost::mutex::scoped_lock lock(mutex_); - - const DicomMap& dicomSummary = instanceToStore.GetSummary(); - const ServerIndex::MetadataMap& metadata = instanceToStore.GetMetadata(); - - int64_t expectedInstances; - const bool hasExpectedInstances = - ComputeExpectedNumberOfInstances(expectedInstances, dicomSummary); - - instanceMetadata.clear(); - - const std::string hashPatient = instanceToStore.GetHasher().HashPatient(); - const std::string hashStudy = instanceToStore.GetHasher().HashStudy(); - const std::string hashSeries = instanceToStore.GetHasher().HashSeries(); - const std::string hashInstance = instanceToStore.GetHasher().HashInstance(); - - try - { - Transaction t(*this); - - IDatabaseWrapper::CreateInstanceResult status; - int64_t instanceId; - - // Check whether this instance is already stored - if (!db_.CreateInstance(status, instanceId, hashPatient, - hashStudy, hashSeries, hashInstance)) - { - // The instance already exists - - if (overwrite) - { - // Overwrite the old instance - LOG(INFO) << "Overwriting instance: " << hashInstance; - db_.DeleteResource(instanceId); - - // Re-create the instance, now that the old one is removed - if (!db_.CreateInstance(status, instanceId, hashPatient, - hashStudy, hashSeries, hashInstance)) - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - // Do nothing if the instance already exists and overwriting is disabled - db_.GetAllMetadata(instanceMetadata, instanceId); - return StoreStatus_AlreadyStored; - } - } - - - // Warn about the creation of new resources. The order must be - // from instance to patient. - - // NB: In theory, could be sped up by grouping the underlying - // calls to "db_.LogChange()". However, this would only have an - // impact when new patient/study/series get created, which - // occurs far less often that creating new instances. The - // positive impact looks marginal in practice. - SignalNewResource(ChangeType_NewInstance, ResourceType_Instance, hashInstance, instanceId); - - if (status.isNewSeries_) - { - SignalNewResource(ChangeType_NewSeries, ResourceType_Series, hashSeries, status.seriesId_); - } - - if (status.isNewStudy_) - { - SignalNewResource(ChangeType_NewStudy, ResourceType_Study, hashStudy, status.studyId_); - } - - if (status.isNewPatient_) - { - SignalNewResource(ChangeType_NewPatient, ResourceType_Patient, hashPatient, status.patientId_); - } - - - // Ensure there is enough room in the storage for the new instance - uint64_t instanceSize = 0; - for (Attachments::const_iterator it = attachments.begin(); - it != attachments.end(); ++it) - { - instanceSize += it->GetCompressedSize(); - } - - Recycle(instanceSize, hashPatient /* don't consider the current patient for recycling */); - - - // Attach the files to the newly created instance - for (Attachments::const_iterator it = attachments.begin(); - it != attachments.end(); ++it) - { - db_.AddAttachment(instanceId, *it); - } - - - { - ResourcesContent content; - - // Populate the tags of the newly-created resources - - content.AddResource(instanceId, ResourceType_Instance, dicomSummary); - - if (status.isNewSeries_) - { - content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary); - } - - if (status.isNewStudy_) - { - content.AddResource(status.studyId_, ResourceType_Study, dicomSummary); - } - - if (status.isNewPatient_) - { - content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary); - } - - - // Attach the user-specified metadata - - for (MetadataMap::const_iterator - it = metadata.begin(); it != metadata.end(); ++it) - { - switch (it->first.first) - { - case ResourceType_Patient: - content.AddMetadata(status.patientId_, it->first.second, it->second); - break; - - case ResourceType_Study: - content.AddMetadata(status.studyId_, it->first.second, it->second); - break; - - case ResourceType_Series: - content.AddMetadata(status.seriesId_, it->first.second, it->second); - break; - - case ResourceType_Instance: - SetInstanceMetadata(content, instanceMetadata, instanceId, - it->first.second, it->second); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - // Attach the auto-computed metadata for the patient/study/series levels - std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); - content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); - content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now); - content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now); - - if (status.isNewSeries_ && - hasExpectedInstances) - { - content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances, - boost::lexical_cast(expectedInstances)); - } - - - // Attach the auto-computed metadata for the instance level, - // reflecting these additions into the input metadata map - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_ReceptionDate, now); - SetInstanceMetadata(content, instanceMetadata, instanceId, MetadataType_Instance_RemoteAet, - instanceToStore.GetOrigin().GetRemoteAetC()); - SetInstanceMetadata(content, instanceMetadata, instanceId, MetadataType_Instance_Origin, - EnumerationToString(instanceToStore.GetOrigin().GetRequestOrigin())); - - - { - std::string s; - - if (instanceToStore.LookupTransferSyntax(s)) - { - // New in Orthanc 1.2.0 - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_TransferSyntax, s); - } - - if (instanceToStore.GetOrigin().LookupRemoteIp(s)) - { - // New in Orthanc 1.4.0 - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_RemoteIp, s); - } - - if (instanceToStore.GetOrigin().LookupCalledAet(s)) - { - // New in Orthanc 1.4.0 - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_CalledAet, s); - } - - if (instanceToStore.GetOrigin().LookupHttpUsername(s)) - { - // New in Orthanc 1.4.0 - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_HttpUsername, s); - } - } - - - const DicomValue* value; - if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && - !value->IsNull() && - !value->IsBinary()) - { - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_SopClassUid, value->GetContent()); - } - - - if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || - (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) - { - if (!value->IsNull() && - !value->IsBinary()) - { - SetInstanceMetadata(content, instanceMetadata, instanceId, - MetadataType_Instance_IndexInSeries, value->GetContent()); - } - } - - - db_.SetResourcesContent(content); - } - - - // Check whether the series of this new instance is now completed - int64_t expectedNumberOfInstances; - if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary)) - { - SeriesStatus seriesStatus = GetSeriesStatus(status.seriesId_, expectedNumberOfInstances); - if (seriesStatus == SeriesStatus_Complete) - { - LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries); - } - } - - - // Mark the parent resources of this instance as unstable - MarkAsUnstable(status.seriesId_, ResourceType_Series, hashSeries); - MarkAsUnstable(status.studyId_, ResourceType_Study, hashStudy); - MarkAsUnstable(status.patientId_, ResourceType_Patient, hashPatient); - - t.Commit(instanceSize); - - return StoreStatus_Success; - } - catch (OrthancException& e) - { - LOG(ERROR) << "EXCEPTION [" << e.What() << "]"; - } - - return StoreStatus_Failure; - } - - - void ServerIndex::GetGlobalStatistics(/* out */ uint64_t& diskSize, - /* out */ uint64_t& uncompressedSize, - /* out */ uint64_t& countPatients, - /* out */ uint64_t& countStudies, - /* out */ uint64_t& countSeries, - /* out */ uint64_t& countInstances) - { - boost::mutex::scoped_lock lock(mutex_); - diskSize = db_.GetTotalCompressedSize(); - uncompressedSize = db_.GetTotalUncompressedSize(); - countPatients = db_.GetResourceCount(ResourceType_Patient); - countStudies = db_.GetResourceCount(ResourceType_Study); - countSeries = db_.GetResourceCount(ResourceType_Series); - countInstances = db_.GetResourceCount(ResourceType_Instance); - } - - - SeriesStatus ServerIndex::GetSeriesStatus(int64_t id, - int64_t expectedNumberOfInstances) - { - std::list values; - db_.GetChildrenMetadata(values, id, MetadataType_Instance_IndexInSeries); - - std::set instances; - - for (std::list::const_iterator - it = values.begin(); it != values.end(); ++it) - { - int64_t index; - - try - { - index = boost::lexical_cast(*it); - } - catch (boost::bad_lexical_cast&) - { - return SeriesStatus_Unknown; - } - - if (!(index > 0 && index <= expectedNumberOfInstances)) - { - // Out-of-range instance index - return SeriesStatus_Inconsistent; - } - - if (instances.find(index) != instances.end()) - { - // Twice the same instance index - return SeriesStatus_Inconsistent; - } - - instances.insert(index); - } - - if (static_cast(instances.size()) == expectedNumberOfInstances) - { - return SeriesStatus_Complete; - } - else - { - return SeriesStatus_Missing; - } - } - - - void ServerIndex::MainDicomTagsToJson(Json::Value& target, - int64_t resourceId, - ResourceType resourceType) - { - DicomMap tags; - db_.GetMainDicomTags(tags, resourceId); - - if (resourceType == ResourceType_Study) - { - DicomMap t1, t2; - tags.ExtractStudyInformation(t1); - tags.ExtractPatientInformation(t2); - - target["MainDicomTags"] = Json::objectValue; - FromDcmtkBridge::ToJson(target["MainDicomTags"], t1, true); - - target["PatientMainDicomTags"] = Json::objectValue; - FromDcmtkBridge::ToJson(target["PatientMainDicomTags"], t2, true); - } - else - { - target["MainDicomTags"] = Json::objectValue; - FromDcmtkBridge::ToJson(target["MainDicomTags"], tags, true); - } - } - - - bool ServerIndex::LookupResource(Json::Value& result, - const std::string& publicId, - ResourceType expectedType) - { - result = Json::objectValue; - - boost::mutex::scoped_lock lock(mutex_); - - // Lookup for the requested resource - int64_t id; - ResourceType type; - std::string parent; - if (!db_.LookupResourceAndParent(id, type, parent, publicId) || - type != expectedType) - { - return false; - } - - // Set information about the parent resource (if it exists) - if (type == ResourceType_Patient) - { - if (!parent.empty()) - { - throw OrthancException(ErrorCode_DatabasePlugin); - } - } - else - { - if (parent.empty()) - { - throw OrthancException(ErrorCode_DatabasePlugin); - } - - switch (type) - { - case ResourceType_Study: - result["ParentPatient"] = parent; - break; - - case ResourceType_Series: - result["ParentStudy"] = parent; - break; - - case ResourceType_Instance: - result["ParentSeries"] = parent; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - // List the children resources - std::list children; - db_.GetChildrenPublicId(children, id); - - if (type != ResourceType_Instance) - { - Json::Value c = Json::arrayValue; - - for (std::list::const_iterator - it = children.begin(); it != children.end(); ++it) - { - c.append(*it); - } - - switch (type) - { - case ResourceType_Patient: - result["Studies"] = c; - break; - - case ResourceType_Study: - result["Series"] = c; - break; - - case ResourceType_Series: - result["Instances"] = c; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - // Extract the metadata - std::map metadata; - db_.GetAllMetadata(metadata, id); - - // Set the resource type - switch (type) - { - case ResourceType_Patient: - result["Type"] = "Patient"; - break; - - case ResourceType_Study: - result["Type"] = "Study"; - break; - - case ResourceType_Series: - { - result["Type"] = "Series"; - - int64_t i; - if (LookupIntegerMetadata(i, metadata, MetadataType_Series_ExpectedNumberOfInstances)) - { - result["ExpectedNumberOfInstances"] = static_cast(i); - result["Status"] = EnumerationToString(GetSeriesStatus(id, i)); - } - else - { - result["ExpectedNumberOfInstances"] = Json::nullValue; - result["Status"] = EnumerationToString(SeriesStatus_Unknown); - } - - break; - } - - case ResourceType_Instance: - { - result["Type"] = "Instance"; - - FileInfo attachment; - if (!db_.LookupAttachment(attachment, id, FileContentType_Dicom)) - { - throw OrthancException(ErrorCode_InternalError); - } - - result["FileSize"] = static_cast(attachment.GetUncompressedSize()); - result["FileUuid"] = attachment.GetUuid(); - - int64_t i; - if (LookupIntegerMetadata(i, metadata, MetadataType_Instance_IndexInSeries)) - { - result["IndexInSeries"] = static_cast(i); - } - else - { - result["IndexInSeries"] = Json::nullValue; - } - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - - // Record the remaining information - result["ID"] = publicId; - MainDicomTagsToJson(result, id, type); - - std::string tmp; - - if (LookupStringMetadata(tmp, metadata, MetadataType_AnonymizedFrom)) - { - result["AnonymizedFrom"] = tmp; - } - - if (LookupStringMetadata(tmp, metadata, MetadataType_ModifiedFrom)) - { - result["ModifiedFrom"] = tmp; - } - - if (type == ResourceType_Patient || - type == ResourceType_Study || - type == ResourceType_Series) - { - result["IsStable"] = !unstableResources_.Contains(id); - - if (LookupStringMetadata(tmp, metadata, MetadataType_LastUpdate)) - { - result["LastUpdate"] = tmp; - } - } - - return true; - } - - - bool ServerIndex::LookupAttachment(FileInfo& attachment, - const std::string& instanceUuid, - FileContentType contentType) - { - boost::mutex::scoped_lock lock(mutex_); - - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, instanceUuid)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - if (db_.LookupAttachment(attachment, id, contentType)) - { - assert(attachment.GetContentType() == contentType); - return true; - } - else - { - return false; - } - } - - - - void ServerIndex::GetAllUuids(std::list& target, - ResourceType resourceType) - { - boost::mutex::scoped_lock lock(mutex_); - db_.GetAllPublicIds(target, resourceType); - } - - - void ServerIndex::GetAllUuids(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit) - { - if (limit == 0) - { - target.clear(); - return; - } - - boost::mutex::scoped_lock lock(mutex_); - db_.GetAllPublicIds(target, resourceType, since, limit); - } - - - template - static void FormatLog(Json::Value& target, - const std::list& log, - const std::string& name, - bool done, - int64_t since, - bool hasLast, - int64_t last) - { - Json::Value items = Json::arrayValue; - for (typename std::list::const_iterator - it = log.begin(); it != log.end(); ++it) - { - Json::Value item; - it->Format(item); - items.append(item); - } - - target = Json::objectValue; - target[name] = items; - target["Done"] = done; - - if (!hasLast) - { - // Best-effort guess of the last index in the sequence - if (log.empty()) - { - last = since; - } - else - { - last = log.back().GetSeq(); - } - } - - target["Last"] = static_cast(last); - } - - - void ServerIndex::GetChanges(Json::Value& target, - int64_t since, - unsigned int maxResults) - { - std::list changes; - bool done; - bool hasLast = false; - int64_t last = 0; - - { - boost::mutex::scoped_lock lock(mutex_); - - // Fix wrt. Orthanc <= 1.3.2: A transaction was missing, as - // "GetLastChange()" involves calls to "GetPublicId()" - Transaction transaction(*this); - - db_.GetChanges(changes, done, since, maxResults); - if (changes.empty()) - { - last = db_.GetLastChangeIndex(); - hasLast = true; - } - - transaction.Commit(0); - } - - FormatLog(target, changes, "Changes", done, since, hasLast, last); - } - - - void ServerIndex::GetLastChange(Json::Value& target) - { - std::list changes; - bool hasLast = false; - int64_t last = 0; - - { - boost::mutex::scoped_lock lock(mutex_); - - // Fix wrt. Orthanc <= 1.3.2: A transaction was missing, as - // "GetLastChange()" involves calls to "GetPublicId()" - Transaction transaction(*this); - - db_.GetLastChange(changes); - if (changes.empty()) - { - last = db_.GetLastChangeIndex(); - hasLast = true; - } - - transaction.Commit(0); - } - - FormatLog(target, changes, "Changes", true, 0, hasLast, last); - } - - - void ServerIndex::LogExportedResource(const std::string& publicId, - const std::string& remoteModality) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction transaction(*this); - - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, publicId)) - { - throw OrthancException(ErrorCode_InexistentItem); - } - - std::string patientId; - std::string studyInstanceUid; - std::string seriesInstanceUid; - std::string sopInstanceUid; - - int64_t currentId = id; - ResourceType currentType = type; - - // Iteratively go up inside the patient/study/series/instance hierarchy - bool done = false; - while (!done) - { - DicomMap map; - db_.GetMainDicomTags(map, currentId); - - switch (currentType) - { - case ResourceType_Patient: - if (map.HasTag(DICOM_TAG_PATIENT_ID)) - { - patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent(); - } - done = true; - break; - - case ResourceType_Study: - if (map.HasTag(DICOM_TAG_STUDY_INSTANCE_UID)) - { - studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent(); - } - currentType = ResourceType_Patient; - break; - - case ResourceType_Series: - if (map.HasTag(DICOM_TAG_SERIES_INSTANCE_UID)) - { - seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent(); - } - currentType = ResourceType_Study; - break; - - case ResourceType_Instance: - if (map.HasTag(DICOM_TAG_SOP_INSTANCE_UID)) - { - sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent(); - } - currentType = ResourceType_Series; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - // If we have not reached the Patient level, find the parent of - // the current resource - if (!done) - { - bool ok = db_.LookupParent(currentId, currentId); - assert(ok); - } - } - - ExportedResource resource(-1, - type, - publicId, - remoteModality, - SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */), - patientId, - studyInstanceUid, - seriesInstanceUid, - sopInstanceUid); - - db_.LogExportedResource(resource); - transaction.Commit(0); - } - - - void ServerIndex::GetExportedResources(Json::Value& target, - int64_t since, - unsigned int maxResults) - { - std::list exported; - bool done; - - { - boost::mutex::scoped_lock lock(mutex_); - db_.GetExportedResources(exported, done, since, maxResults); - } - - FormatLog(target, exported, "Exports", done, since, false, -1); - } - - - void ServerIndex::GetLastExportedResource(Json::Value& target) - { - std::list exported; - - { - boost::mutex::scoped_lock lock(mutex_); - db_.GetLastExportedResource(exported); - } - - FormatLog(target, exported, "Exports", true, 0, false, -1); - } - - - bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize) - { - if (maximumStorageSize_ != 0) - { - assert(maximumStorageSize_ >= instanceSize); - - if (db_.IsDiskSizeAbove(maximumStorageSize_ - instanceSize)) - { - return true; - } - } - - if (maximumPatients_ != 0) - { - uint64_t patientCount = db_.GetResourceCount(ResourceType_Patient); - if (patientCount > maximumPatients_) - { - return true; - } - } - - return false; - } - - - void ServerIndex::Recycle(uint64_t instanceSize, - const std::string& newPatientId) - { - if (!IsRecyclingNeeded(instanceSize)) - { - return; - } - - // Check whether other DICOM instances from this patient are - // already stored - int64_t patientToAvoid; - ResourceType type; - bool hasPatientToAvoid = db_.LookupResource(patientToAvoid, type, newPatientId); - - if (hasPatientToAvoid && type != ResourceType_Patient) - { - throw OrthancException(ErrorCode_InternalError); - } - - // Iteratively select patient to remove until there is enough - // space in the DICOM store - int64_t patientToRecycle; - while (true) - { - // If other instances of this patient are already in the store, - // we must avoid to recycle them - bool ok = hasPatientToAvoid ? - db_.SelectPatientToRecycle(patientToRecycle, patientToAvoid) : - db_.SelectPatientToRecycle(patientToRecycle); - - if (!ok) - { - throw OrthancException(ErrorCode_FullStorage); - } - - VLOG(1) << "Recycling one patient"; - db_.DeleteResource(patientToRecycle); - - if (!IsRecyclingNeeded(instanceSize)) - { - // OK, we're done - break; - } - } - } - - void ServerIndex::SetMaximumPatientCount(unsigned int count) - { - boost::mutex::scoped_lock lock(mutex_); - maximumPatients_ = count; - - if (count == 0) - { - LOG(WARNING) << "No limit on the number of stored patients"; - } - else - { - LOG(WARNING) << "At most " << count << " patients will be stored"; - } - - StandaloneRecycling(); - } - - void ServerIndex::SetMaximumStorageSize(uint64_t size) - { - boost::mutex::scoped_lock lock(mutex_); - maximumStorageSize_ = size; - - if (size == 0) - { - LOG(WARNING) << "No limit on the size of the storage area"; - } - else - { - LOG(WARNING) << "At most " << (size / MEGA_BYTES) << "MB will be used for the storage area"; - } - - StandaloneRecycling(); - } - - - void ServerIndex::StandaloneRecycling() - { - // WARNING: No mutex here, do not include this as a public method - Transaction t(*this); - Recycle(0, ""); - t.Commit(0); - } - - - bool ServerIndex::IsProtectedPatient(const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - - // Lookup for the requested resource - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, publicId) || - type != ResourceType_Patient) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - return db_.IsProtectedPatient(id); - } - - - void ServerIndex::SetProtectedPatient(const std::string& publicId, - bool isProtected) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction transaction(*this); - - // Lookup for the requested resource - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, publicId) || - type != ResourceType_Patient) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - db_.SetProtectedPatient(id, isProtected); - transaction.Commit(0); - - if (isProtected) - LOG(INFO) << "Patient " << publicId << " has been protected"; - else - LOG(INFO) << "Patient " << publicId << " has been unprotected"; - } - - - void ServerIndex::GetChildren(std::list& result, - const std::string& publicId) - { - result.clear(); - - boost::mutex::scoped_lock lock(mutex_); - - ResourceType type; - int64_t resource; - if (!db_.LookupResource(resource, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - if (type == ResourceType_Instance) - { - // An instance cannot have a child - throw OrthancException(ErrorCode_BadParameterType); - } - - std::list tmp; - db_.GetChildrenInternalId(tmp, resource); - - for (std::list::const_iterator - it = tmp.begin(); it != tmp.end(); ++it) - { - result.push_back(db_.GetPublicId(*it)); - } - } - - - void ServerIndex::GetChildInstances(std::list& result, - const std::string& publicId) - { - result.clear(); - - boost::mutex::scoped_lock lock(mutex_); - - ResourceType type; - int64_t top; - if (!db_.LookupResource(top, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - if (type == ResourceType_Instance) - { - // The resource is already an instance: Do not go down the hierarchy - result.push_back(publicId); - return; - } - - std::stack toExplore; - toExplore.push(top); - - std::list tmp; - - while (!toExplore.empty()) - { - // Get the internal ID of the current resource - int64_t resource = toExplore.top(); - toExplore.pop(); - - if (db_.GetResourceType(resource) == ResourceType_Instance) - { - result.push_back(db_.GetPublicId(resource)); - } - else - { - // Tag all the children of this resource as to be explored - db_.GetChildrenInternalId(tmp, resource); - for (std::list::const_iterator - it = tmp.begin(); it != tmp.end(); ++it) - { - toExplore.push(*it); - } - } - } - } - - - void ServerIndex::SetMetadata(const std::string& publicId, - MetadataType type, - const std::string& value) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction t(*this); - - ResourceType rtype; - int64_t id; - if (!db_.LookupResource(id, rtype, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - db_.SetMetadata(id, type, value); - - if (IsUserMetadata(type)) - { - LogChange(id, ChangeType_UpdatedMetadata, rtype, publicId); - } - - t.Commit(0); - } - - - void ServerIndex::DeleteMetadata(const std::string& publicId, - MetadataType type) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction t(*this); - - ResourceType rtype; - int64_t id; - if (!db_.LookupResource(id, rtype, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - db_.DeleteMetadata(id, type); - - if (IsUserMetadata(type)) - { - LogChange(id, ChangeType_UpdatedMetadata, rtype, publicId); - } - - t.Commit(0); - } - - - bool ServerIndex::LookupMetadata(std::string& target, - const std::string& publicId, - MetadataType type) - { - boost::mutex::scoped_lock lock(mutex_); - - ResourceType rtype; - int64_t id; - if (!db_.LookupResource(id, rtype, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - return db_.LookupMetadata(target, id, type); - } - - - void ServerIndex::GetAllMetadata(std::map& target, - const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - - ResourceType type; - int64_t id; - if (!db_.LookupResource(id, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - return db_.GetAllMetadata(target, id); - } - - - void ServerIndex::ListAvailableAttachments(std::list& target, - const std::string& publicId, - ResourceType expectedType) - { - boost::mutex::scoped_lock lock(mutex_); - - ResourceType type; - int64_t id; - if (!db_.LookupResource(id, type, publicId) || - expectedType != type) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - db_.ListAvailableAttachments(target, id); - } - - - bool ServerIndex::LookupParent(std::string& target, - const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - - ResourceType type; - int64_t id; - if (!db_.LookupResource(id, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - int64_t parentId; - if (db_.LookupParent(parentId, id)) - { - target = db_.GetPublicId(parentId); - return true; - } - else - { - return false; - } - } - - - uint64_t ServerIndex::IncrementGlobalSequence(GlobalProperty sequence) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction transaction(*this); - - uint64_t seq = IncrementGlobalSequenceInternal(sequence); - transaction.Commit(0); - - return seq; - } - - - - void ServerIndex::LogChange(ChangeType changeType, - const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction transaction(*this); - - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - LogChange(id, changeType, type, publicId); - transaction.Commit(0); - } - - - void ServerIndex::DeleteChanges() - { - boost::mutex::scoped_lock lock(mutex_); - - Transaction transaction(*this); - db_.ClearChanges(); - transaction.Commit(0); - } - - void ServerIndex::DeleteExportedResources() - { - boost::mutex::scoped_lock lock(mutex_); - - Transaction transaction(*this); - db_.ClearExportedResources(); - transaction.Commit(0); - } - - - void ServerIndex::GetResourceStatistics(/* out */ ResourceType& type, - /* out */ uint64_t& diskSize, - /* out */ uint64_t& uncompressedSize, - /* out */ unsigned int& countStudies, - /* out */ unsigned int& countSeries, - /* out */ unsigned int& countInstances, - /* out */ uint64_t& dicomDiskSize, - /* out */ uint64_t& dicomUncompressedSize, - const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - - int64_t top; - if (!db_.LookupResource(top, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - std::stack toExplore; - toExplore.push(top); - - countInstances = 0; - countSeries = 0; - countStudies = 0; - diskSize = 0; - uncompressedSize = 0; - dicomDiskSize = 0; - dicomUncompressedSize = 0; - - while (!toExplore.empty()) - { - // Get the internal ID of the current resource - int64_t resource = toExplore.top(); - toExplore.pop(); - - ResourceType thisType = db_.GetResourceType(resource); - - std::list f; - db_.ListAvailableAttachments(f, resource); - - for (std::list::const_iterator - it = f.begin(); it != f.end(); ++it) - { - FileInfo attachment; - if (db_.LookupAttachment(attachment, resource, *it)) - { - if (attachment.GetContentType() == FileContentType_Dicom) - { - dicomDiskSize += attachment.GetCompressedSize(); - dicomUncompressedSize += attachment.GetUncompressedSize(); - } - - diskSize += attachment.GetCompressedSize(); - uncompressedSize += attachment.GetUncompressedSize(); - } - } - - if (thisType == ResourceType_Instance) - { - countInstances++; - } - else - { - switch (thisType) - { - case ResourceType_Study: - countStudies++; - break; - - case ResourceType_Series: - countSeries++; - break; - - default: - break; - } - - // Tag all the children of this resource as to be explored - std::list tmp; - db_.GetChildrenInternalId(tmp, resource); - for (std::list::const_iterator - it = tmp.begin(); it != tmp.end(); ++it) - { - toExplore.push(*it); - } - } - } - - if (countStudies == 0) - { - countStudies = 1; - } - - if (countSeries == 0) - { - countSeries = 1; - } - } - - - void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that, - unsigned int threadSleep) - { - int stableAge; - - { - OrthancConfiguration::ReaderLock lock; - stableAge = lock.GetConfiguration().GetUnsignedIntegerParameter("StableAge", 60); - } - - if (stableAge <= 0) - { - stableAge = 60; - } - - LOG(INFO) << "Starting the monitor for stable resources (stable age = " << stableAge << ")"; - - while (!that->done_) - { - // Check for stable resources each few seconds - boost::this_thread::sleep(boost::posix_time::milliseconds(threadSleep)); - - boost::mutex::scoped_lock lock(that->mutex_); - - while (!that->unstableResources_.IsEmpty() && - that->unstableResources_.GetOldestPayload().GetAge() > static_cast(stableAge)) - { - // This DICOM resource has not received any new instance for - // some time. It can be considered as stable. - - UnstableResourcePayload payload; - int64_t id = that->unstableResources_.RemoveOldest(payload); - - // Ensure that the resource is still existing before logging the change - if (that->db_.IsExistingResource(id)) - { - switch (payload.GetResourceType()) - { - case ResourceType_Patient: - that->LogChange(id, ChangeType_StablePatient, ResourceType_Patient, payload.GetPublicId()); - break; - - case ResourceType_Study: - that->LogChange(id, ChangeType_StableStudy, ResourceType_Study, payload.GetPublicId()); - break; - - case ResourceType_Series: - that->LogChange(id, ChangeType_StableSeries, ResourceType_Series, payload.GetPublicId()); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - //LOG(INFO) << "Stable resource: " << EnumerationToString(payload.type_) << " " << id; - } - } - } - - LOG(INFO) << "Closing the monitor thread for stable resources"; - } - - - void ServerIndex::MarkAsUnstable(int64_t id, - Orthanc::ResourceType type, - const std::string& publicId) - { - // WARNING: Before calling this method, "mutex_" must be locked. - - assert(type == Orthanc::ResourceType_Patient || - type == Orthanc::ResourceType_Study || - type == Orthanc::ResourceType_Series); - - UnstableResourcePayload payload(type, publicId); - unstableResources_.AddOrMakeMostRecent(id, payload); - //LOG(INFO) << "Unstable resource: " << EnumerationToString(type) << " " << id; - - LogChange(id, ChangeType_NewChildInstance, type, publicId); - } - - - - void ServerIndex::LookupIdentifierExact(std::vector& result, - ResourceType level, - const DicomTag& tag, - const std::string& value) - { - assert((level == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) || - (level == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) || - (level == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) || - (level == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) || - (level == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID)); - - result.clear(); - - DicomTagConstraint c(tag, ConstraintType_Equal, value, true, true); - - std::vector query; - query.push_back(c.ConvertToDatabaseConstraint(level, DicomTagType_Identifier)); - - std::list tmp; - - { - boost::mutex::scoped_lock lock(mutex_); - db_.ApplyLookupResources(tmp, NULL, query, level, 0); - } - - CopyListToVector(result, tmp); - } - - - StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment, - const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - - Transaction t(*this); - - ResourceType resourceType; - int64_t resourceId; - if (!db_.LookupResource(resourceId, resourceType, publicId)) - { - return StoreStatus_Failure; // Inexistent resource - } - - // Remove possible previous attachment - db_.DeleteAttachment(resourceId, attachment.GetContentType()); - - // Locate the patient of the target resource - int64_t patientId = resourceId; - for (;;) - { - int64_t parent; - if (db_.LookupParent(parent, patientId)) - { - // We have not reached the patient level yet - patientId = parent; - } - else - { - // We have reached the patient level - break; - } - } - - // Possibly apply the recycling mechanism while preserving this patient - assert(db_.GetResourceType(patientId) == ResourceType_Patient); - Recycle(attachment.GetCompressedSize(), db_.GetPublicId(patientId)); - - db_.AddAttachment(resourceId, attachment); - - if (IsUserContentType(attachment.GetContentType())) - { - LogChange(resourceId, ChangeType_UpdatedAttachment, resourceType, publicId); - } - - t.Commit(attachment.GetCompressedSize()); - - return StoreStatus_Success; - } - - - void ServerIndex::DeleteAttachment(const std::string& publicId, - FileContentType type) - { - boost::mutex::scoped_lock lock(mutex_); - Transaction t(*this); - - ResourceType rtype; - int64_t id; - if (!db_.LookupResource(id, rtype, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - db_.DeleteAttachment(id, type); - - if (IsUserContentType(type)) - { - LogChange(id, ChangeType_UpdatedAttachment, rtype, publicId); - } - - t.Commit(0); - } - - - void ServerIndex::SetGlobalProperty(GlobalProperty property, - const std::string& value) - { - boost::mutex::scoped_lock lock(mutex_); - - Transaction transaction(*this); - db_.SetGlobalProperty(property, value); - transaction.Commit(0); - } - - - bool ServerIndex::LookupGlobalProperty(std::string& value, - GlobalProperty property) - { - boost::mutex::scoped_lock lock(mutex_); - return db_.LookupGlobalProperty(value, property); - } - - - std::string ServerIndex::GetGlobalProperty(GlobalProperty property, - const std::string& defaultValue) - { - std::string value; - - if (LookupGlobalProperty(value, property)) - { - return value; - } - else - { - return defaultValue; - } - } - - - bool ServerIndex::GetMainDicomTags(DicomMap& result, - const std::string& publicId, - ResourceType expectedType, - ResourceType levelOfInterest) - { - // Yes, the following test could be shortened, but we wish to make it as clear as possible - if (!(expectedType == ResourceType_Patient && levelOfInterest == ResourceType_Patient) && - !(expectedType == ResourceType_Study && levelOfInterest == ResourceType_Patient) && - !(expectedType == ResourceType_Study && levelOfInterest == ResourceType_Study) && - !(expectedType == ResourceType_Series && levelOfInterest == ResourceType_Series) && - !(expectedType == ResourceType_Instance && levelOfInterest == ResourceType_Instance)) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - result.Clear(); - - boost::mutex::scoped_lock lock(mutex_); - - // Lookup for the requested resource - int64_t id; - ResourceType type; - if (!db_.LookupResource(id, type, publicId) || - type != expectedType) - { - return false; - } - - if (type == ResourceType_Study) - { - DicomMap tmp; - db_.GetMainDicomTags(tmp, id); - - switch (levelOfInterest) - { - case ResourceType_Patient: - tmp.ExtractPatientInformation(result); - return true; - - case ResourceType_Study: - tmp.ExtractStudyInformation(result); - return true; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - db_.GetMainDicomTags(result, id); - return true; - } - } - - - bool ServerIndex::GetAllMainDicomTags(DicomMap& result, - const std::string& instancePublicId) - { - result.Clear(); - - boost::mutex::scoped_lock lock(mutex_); - - // Lookup for the requested resource - int64_t instance; - ResourceType type; - if (!db_.LookupResource(instance, type, instancePublicId) || - type != ResourceType_Instance) - { - return false; - } - else - { - DicomMap tmp; - - db_.GetMainDicomTags(tmp, instance); - result.Merge(tmp); - - int64_t series; - if (!db_.LookupParent(series, instance)) - { - throw OrthancException(ErrorCode_InternalError); - } - - tmp.Clear(); - db_.GetMainDicomTags(tmp, series); - result.Merge(tmp); - - int64_t study; - if (!db_.LookupParent(study, series)) - { - throw OrthancException(ErrorCode_InternalError); - } - - tmp.Clear(); - db_.GetMainDicomTags(tmp, study); - result.Merge(tmp); - -#ifndef NDEBUG - { - // Sanity test to check that all the main DICOM tags from the - // patient level are copied at the study level - - int64_t patient; - if (!db_.LookupParent(patient, study)) - { - throw OrthancException(ErrorCode_InternalError); - } - - tmp.Clear(); - db_.GetMainDicomTags(tmp, study); - - std::set patientTags; - tmp.GetTags(patientTags); - - for (std::set::const_iterator - it = patientTags.begin(); it != patientTags.end(); ++it) - { - assert(result.HasTag(*it)); - } - } -#endif - - return true; - } - } - - - bool ServerIndex::LookupResourceType(ResourceType& type, - const std::string& publicId) - { - boost::mutex::scoped_lock lock(mutex_); - - int64_t id; - return db_.LookupResource(id, type, publicId); - } - - - unsigned int ServerIndex::GetDatabaseVersion() - { - boost::mutex::scoped_lock lock(mutex_); - return db_.GetDatabaseVersion(); - } - - - bool ServerIndex::LookupParent(std::string& target, - const std::string& publicId, - ResourceType parentType) - { - boost::mutex::scoped_lock lock(mutex_); - - ResourceType type; - int64_t id; - if (!db_.LookupResource(id, type, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - while (type != parentType) - { - int64_t parentId; - - if (type == ResourceType_Patient || // Cannot further go up in hierarchy - !db_.LookupParent(parentId, id)) - { - return false; - } - - id = parentId; - type = GetParentResourceType(type); - } - - target = db_.GetPublicId(id); - return true; - } - - - void ServerIndex::ReconstructInstance(ParsedDicomFile& dicom) - { - DicomMap summary; - dicom.ExtractDicomSummary(summary); - - DicomInstanceHasher hasher(summary); - - boost::mutex::scoped_lock lock(mutex_); - - try - { - Transaction t(*this); - - int64_t patient = -1, study = -1, series = -1, instance = -1; - - ResourceType dummy; - if (!db_.LookupResource(patient, dummy, hasher.HashPatient()) || - !db_.LookupResource(study, dummy, hasher.HashStudy()) || - !db_.LookupResource(series, dummy, hasher.HashSeries()) || - !db_.LookupResource(instance, dummy, hasher.HashInstance()) || - patient == -1 || - study == -1 || - series == -1 || - instance == -1) - { - throw OrthancException(ErrorCode_InternalError); - } - - db_.ClearMainDicomTags(patient); - db_.ClearMainDicomTags(study); - db_.ClearMainDicomTags(series); - db_.ClearMainDicomTags(instance); - - { - ResourcesContent content; - content.AddResource(patient, ResourceType_Patient, summary); - content.AddResource(study, ResourceType_Study, summary); - content.AddResource(series, ResourceType_Series, summary); - content.AddResource(instance, ResourceType_Instance, summary); - db_.SetResourcesContent(content); - } - - { - std::string s; - if (dicom.LookupTransferSyntax(s)) - { - db_.SetMetadata(instance, MetadataType_Instance_TransferSyntax, s); - } - } - - const DicomValue* value; - if ((value = summary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && - !value->IsNull() && - !value->IsBinary()) - { - db_.SetMetadata(instance, MetadataType_Instance_SopClassUid, value->GetContent()); - } - - t.Commit(0); // No change in the DB size - } - catch (OrthancException& e) - { - LOG(ERROR) << "EXCEPTION [" << e.What() << "]"; - } - } - - - void ServerIndex::NormalizeLookup(std::vector& target, - const DatabaseLookup& source, - ResourceType queryLevel) const - { - assert(mainDicomTagsRegistry_.get() != NULL); - - target.clear(); - target.reserve(source.GetConstraintsCount()); - - for (size_t i = 0; i < source.GetConstraintsCount(); i++) - { - ResourceType level; - DicomTagType type; - - mainDicomTagsRegistry_->LookupTag(level, type, source.GetConstraint(i).GetTag()); - - if (type == DicomTagType_Identifier || - type == DicomTagType_Main) - { - // Use the fact that patient-level tags are copied at the study level - if (level == ResourceType_Patient && - queryLevel != ResourceType_Patient) - { - level = ResourceType_Study; - } - - target.push_back(source.GetConstraint(i).ConvertToDatabaseConstraint(level, type)); - } - } - } - - - void ServerIndex::ApplyLookupResources(std::vector& resourcesId, - std::vector* instancesId, - const DatabaseLookup& lookup, - ResourceType queryLevel, - size_t limit) - { - std::vector normalized; - NormalizeLookup(normalized, lookup, queryLevel); - - std::list resourcesList, instancesList; - - { - boost::mutex::scoped_lock lock(mutex_); - - if (instancesId == NULL) - { - db_.ApplyLookupResources(resourcesList, NULL, normalized, queryLevel, limit); - } - else - { - db_.ApplyLookupResources(resourcesList, &instancesList, normalized, queryLevel, limit); - } - } - - CopyListToVector(resourcesId, resourcesList); - - if (instancesId != NULL) - { - CopyListToVector(*instancesId, instancesList); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerIndex.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,285 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/Cache/LeastRecentlyUsedIndex.h" -#include "../Core/DicomFormat/DicomMap.h" - -#include "Database/IDatabaseWrapper.h" - -#include -#include - -namespace Orthanc -{ - class DatabaseLookup; - class DicomInstanceToStore; - class ParsedDicomFile; - class ServerContext; - - class ServerIndex : public boost::noncopyable - { - public: - typedef std::list Attachments; - typedef std::map, std::string> MetadataMap; - - private: - class Listener; - class Transaction; - class UnstableResourcePayload; - class MainDicomTagsRegistry; - - bool done_; - boost::mutex mutex_; - boost::thread flushThread_; - boost::thread unstableResourcesMonitorThread_; - - std::unique_ptr listener_; - IDatabaseWrapper& db_; - LeastRecentlyUsedIndex unstableResources_; - - uint64_t maximumStorageSize_; - unsigned int maximumPatients_; - std::unique_ptr mainDicomTagsRegistry_; - - static void FlushThread(ServerIndex* that, - unsigned int threadSleep); - - static void UnstableResourcesMonitorThread(ServerIndex* that, - unsigned int threadSleep); - - void MainDicomTagsToJson(Json::Value& result, - int64_t resourceId, - ResourceType resourceType); - - bool IsRecyclingNeeded(uint64_t instanceSize); - - void Recycle(uint64_t instanceSize, - const std::string& newPatientId); - - void StandaloneRecycling(); - - void MarkAsUnstable(int64_t id, - Orthanc::ResourceType type, - const std::string& publicId); - - void LogChange(int64_t internalId, - ChangeType changeType, - ResourceType resourceType, - const std::string& publicId); - - void SignalNewResource(ChangeType changeType, - ResourceType level, - const std::string& publicId, - int64_t internalId); - - uint64_t IncrementGlobalSequenceInternal(GlobalProperty property); - - void NormalizeLookup(std::vector& target, - const DatabaseLookup& source, - ResourceType level) const; - - SeriesStatus GetSeriesStatus(int64_t id, - int64_t expectedNumberOfInstances); - - public: - ServerIndex(ServerContext& context, - IDatabaseWrapper& database, - unsigned int threadSleep); - - ~ServerIndex(); - - void Stop(); - - uint64_t GetMaximumStorageSize() const - { - return maximumStorageSize_; - } - - uint64_t GetMaximumPatientCount() const - { - return maximumPatients_; - } - - // "size == 0" means no limit on the storage size - void SetMaximumStorageSize(uint64_t size); - - // "count == 0" means no limit on the number of patients - void SetMaximumPatientCount(unsigned int count); - - StoreStatus Store(std::map& instanceMetadata, - DicomInstanceToStore& instance, - const Attachments& attachments, - bool overwrite); - - void GetGlobalStatistics(/* out */ uint64_t& diskSize, - /* out */ uint64_t& uncompressedSize, - /* out */ uint64_t& countPatients, - /* out */ uint64_t& countStudies, - /* out */ uint64_t& countSeries, - /* out */ uint64_t& countInstances); - - bool LookupResource(Json::Value& result, - const std::string& publicId, - ResourceType expectedType); - - bool LookupAttachment(FileInfo& attachment, - const std::string& instanceUuid, - FileContentType contentType); - - void GetAllUuids(std::list& target, - ResourceType resourceType); - - void GetAllUuids(std::list& target, - ResourceType resourceType, - size_t since, - size_t limit); - - bool DeleteResource(Json::Value& target /* out */, - const std::string& uuid, - ResourceType expectedType); - - void GetChanges(Json::Value& target, - int64_t since, - unsigned int maxResults); - - void GetLastChange(Json::Value& target); - - void LogExportedResource(const std::string& publicId, - const std::string& remoteModality); - - void GetExportedResources(Json::Value& target, - int64_t since, - unsigned int maxResults); - - void GetLastExportedResource(Json::Value& target); - - bool IsProtectedPatient(const std::string& publicId); - - void SetProtectedPatient(const std::string& publicId, - bool isProtected); - - void GetChildren(std::list& result, - const std::string& publicId); - - void GetChildInstances(std::list& result, - const std::string& publicId); - - void SetMetadata(const std::string& publicId, - MetadataType type, - const std::string& value); - - void DeleteMetadata(const std::string& publicId, - MetadataType type); - - void GetAllMetadata(std::map& target, - const std::string& publicId); - - bool LookupMetadata(std::string& target, - const std::string& publicId, - MetadataType type); - - void ListAvailableAttachments(std::list& target, - const std::string& publicId, - ResourceType expectedType); - - bool LookupParent(std::string& target, - const std::string& publicId); - - uint64_t IncrementGlobalSequence(GlobalProperty sequence); - - void LogChange(ChangeType changeType, - const std::string& publicId); - - void DeleteChanges(); - - void DeleteExportedResources(); - - void GetResourceStatistics(/* out */ ResourceType& type, - /* out */ uint64_t& diskSize, - /* out */ uint64_t& uncompressedSize, - /* out */ unsigned int& countStudies, - /* out */ unsigned int& countSeries, - /* out */ unsigned int& countInstances, - /* out */ uint64_t& dicomDiskSize, - /* out */ uint64_t& dicomUncompressedSize, - const std::string& publicId); - - void LookupIdentifierExact(std::vector& result, - ResourceType level, - const DicomTag& tag, - const std::string& value); - - StoreStatus AddAttachment(const FileInfo& attachment, - const std::string& publicId); - - void DeleteAttachment(const std::string& publicId, - FileContentType type); - - void SetGlobalProperty(GlobalProperty property, - const std::string& value); - - bool LookupGlobalProperty(std::string& value, - GlobalProperty property); - - std::string GetGlobalProperty(GlobalProperty property, - const std::string& defaultValue); - - bool GetMainDicomTags(DicomMap& result, - const std::string& publicId, - ResourceType expectedType, - ResourceType levelOfInterest); - - // Only applicable at the instance level - bool GetAllMainDicomTags(DicomMap& result, - const std::string& instancePublicId); - - bool LookupResourceType(ResourceType& type, - const std::string& publicId); - - unsigned int GetDatabaseVersion(); - - bool LookupParent(std::string& target, - const std::string& publicId, - ResourceType parentType); - - void ReconstructInstance(ParsedDicomFile& dicom); - - void ApplyLookupResources(std::vector& resourcesId, - std::vector* instancesId, // Can be NULL if not needed - const DatabaseLookup& lookup, - ResourceType queryLevel, - size_t limit); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1114 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "ArchiveJob.h" - -#include "../../Core/Cache/SharedArchive.h" -#include "../../Core/Compression/HierarchicalZipWriter.h" -#include "../../Core/DicomParsing/DicomDirWriter.h" -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/Logging.h" -#include "../../Core/OrthancException.h" -#include "../OrthancConfiguration.h" -#include "../ServerContext.h" - -#include - -#if defined(_MSC_VER) -#define snprintf _snprintf -#endif - -static const uint64_t MEGA_BYTES = 1024 * 1024; -static const uint64_t GIGA_BYTES = 1024 * 1024 * 1024; - -static const char* const MEDIA_IMAGES_FOLDER = "IMAGES"; -static const char* const KEY_DESCRIPTION = "Description"; -static const char* const KEY_INSTANCES_COUNT = "InstancesCount"; -static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB"; -static const char* const KEY_TRANSCODE = "Transcode"; - - -namespace Orthanc -{ - static bool IsZip64Required(uint64_t uncompressedSize, - unsigned int countInstances) - { - static const uint64_t SAFETY_MARGIN = 64 * MEGA_BYTES; // Should be large enough to hold DICOMDIR - static const unsigned int FILES_MARGIN = 10; - - /** - * Determine whether ZIP64 is required. Original ZIP format can - * store up to 2GB of data (some implementation supporting up to - * 4GB of data), and up to 65535 files. - * https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64 - **/ - - const bool isZip64 = (uncompressedSize >= 2 * GIGA_BYTES - SAFETY_MARGIN || - countInstances >= 65535 - FILES_MARGIN); - - LOG(INFO) << "Creating a ZIP file with " << countInstances << " files of size " - << (uncompressedSize / MEGA_BYTES) << "MB using the " - << (isZip64 ? "ZIP64" : "ZIP32") << " file format"; - - return isZip64; - } - - - class ArchiveJob::ResourceIdentifiers : public boost::noncopyable - { - private: - ResourceType level_; - std::string patient_; - std::string study_; - std::string series_; - std::string instance_; - - static void GoToParent(ServerIndex& index, - std::string& current) - { - std::string tmp; - - if (index.LookupParent(tmp, current)) - { - current = tmp; - } - else - { - throw OrthancException(ErrorCode_UnknownResource); - } - } - - - public: - ResourceIdentifiers(ServerIndex& index, - const std::string& publicId) - { - if (!index.LookupResourceType(level_, publicId)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - std::string current = publicId;; - switch (level_) // Do not add "break" below! - { - case ResourceType_Instance: - instance_ = current; - GoToParent(index, current); - - case ResourceType_Series: - series_ = current; - GoToParent(index, current); - - case ResourceType_Study: - study_ = current; - GoToParent(index, current); - - case ResourceType_Patient: - patient_ = current; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - ResourceType GetLevel() const - { - return level_; - } - - const std::string& GetIdentifier(ResourceType level) const - { - // Some sanity check to ensure enumerations are not altered - assert(ResourceType_Patient < ResourceType_Study); - assert(ResourceType_Study < ResourceType_Series); - assert(ResourceType_Series < ResourceType_Instance); - - if (level > level_) - { - throw OrthancException(ErrorCode_InternalError); - } - - switch (level) - { - case ResourceType_Patient: - return patient_; - - case ResourceType_Study: - return study_; - - case ResourceType_Series: - return series_; - - case ResourceType_Instance: - return instance_; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - }; - - - class ArchiveJob::IArchiveVisitor : public boost::noncopyable - { - public: - virtual ~IArchiveVisitor() - { - } - - virtual void Open(ResourceType level, - const std::string& publicId) = 0; - - virtual void Close() = 0; - - virtual void AddInstance(const std::string& instanceId, - const FileInfo& dicom) = 0; - }; - - - class ArchiveJob::ArchiveIndex : public boost::noncopyable - { - private: - struct Instance - { - std::string id_; - FileInfo dicom_; - - Instance(const std::string& id, - const FileInfo& dicom) : - id_(id), dicom_(dicom) - { - } - }; - - // A "NULL" value for ArchiveIndex indicates a non-expanded node - typedef std::map Resources; - - ResourceType level_; - Resources resources_; // Only at patient/study/series level - std::list instances_; // Only at instance level - - - void AddResourceToExpand(ServerIndex& index, - const std::string& id) - { - if (level_ == ResourceType_Instance) - { - FileInfo tmp; - if (index.LookupAttachment(tmp, id, FileContentType_Dicom)) - { - instances_.push_back(Instance(id, tmp)); - } - } - else - { - resources_[id] = NULL; - } - } - - - public: - ArchiveIndex(ResourceType level) : - level_(level) - { - } - - ~ArchiveIndex() - { - for (Resources::iterator it = resources_.begin(); - it != resources_.end(); ++it) - { - delete it->second; - } - } - - - void Add(ServerIndex& index, - const ResourceIdentifiers& resource) - { - const std::string& id = resource.GetIdentifier(level_); - Resources::iterator previous = resources_.find(id); - - if (level_ == ResourceType_Instance) - { - AddResourceToExpand(index, id); - } - else if (resource.GetLevel() == level_) - { - // Mark this resource for further expansion - if (previous != resources_.end()) - { - delete previous->second; - } - - resources_[id] = NULL; - } - else if (previous == resources_.end()) - { - // This is the first time we meet this resource - std::unique_ptr child(new ArchiveIndex(GetChildResourceType(level_))); - child->Add(index, resource); - resources_[id] = child.release(); - } - else if (previous->second != NULL) - { - previous->second->Add(index, resource); - } - else - { - // Nothing to do: This item is marked for further expansion - } - } - - - void Expand(ServerIndex& index) - { - if (level_ == ResourceType_Instance) - { - // Expanding an instance node makes no sense - return; - } - - for (Resources::iterator it = resources_.begin(); - it != resources_.end(); ++it) - { - if (it->second == NULL) - { - // This is resource is marked for expansion - std::list children; - index.GetChildren(children, it->first); - - std::unique_ptr child(new ArchiveIndex(GetChildResourceType(level_))); - - for (std::list::const_iterator - it2 = children.begin(); it2 != children.end(); ++it2) - { - child->AddResourceToExpand(index, *it2); - } - - it->second = child.release(); - } - - assert(it->second != NULL); - it->second->Expand(index); - } - } - - - void Apply(IArchiveVisitor& visitor) const - { - if (level_ == ResourceType_Instance) - { - for (std::list::const_iterator - it = instances_.begin(); it != instances_.end(); ++it) - { - visitor.AddInstance(it->id_, it->dicom_); - } - } - else - { - for (Resources::const_iterator it = resources_.begin(); - it != resources_.end(); ++it) - { - assert(it->second != NULL); // There must have been a call to "Expand()" - visitor.Open(level_, it->first); - it->second->Apply(visitor); - visitor.Close(); - } - } - } - }; - - - - class ArchiveJob::ZipCommands : public boost::noncopyable - { - private: - enum Type - { - Type_OpenDirectory, - Type_CloseDirectory, - Type_WriteInstance - }; - - class Command : public boost::noncopyable - { - private: - Type type_; - std::string filename_; - std::string instanceId_; - FileInfo info_; - - public: - explicit Command(Type type) : - type_(type) - { - assert(type_ == Type_CloseDirectory); - } - - Command(Type type, - const std::string& filename) : - type_(type), - filename_(filename) - { - assert(type_ == Type_OpenDirectory); - } - - Command(Type type, - const std::string& filename, - const std::string& instanceId, - const FileInfo& info) : - type_(type), - filename_(filename), - instanceId_(instanceId), - info_(info) - { - assert(type_ == Type_WriteInstance); - } - - void Apply(HierarchicalZipWriter& writer, - ServerContext& context, - DicomDirWriter* dicomDir, - const std::string& dicomDirFolder, - bool transcode, - DicomTransferSyntax transferSyntax) const - { - switch (type_) - { - case Type_OpenDirectory: - writer.OpenDirectory(filename_.c_str()); - break; - - case Type_CloseDirectory: - writer.CloseDirectory(); - break; - - case Type_WriteInstance: - { - std::string content; - - try - { - context.ReadAttachment(content, info_); - } - catch (OrthancException& e) - { - LOG(WARNING) << "An instance was removed after the job was issued: " << instanceId_; - return; - } - - //boost::this_thread::sleep(boost::posix_time::milliseconds(300)); - - writer.OpenFile(filename_.c_str()); - - bool transcodeSuccess = false; - - std::unique_ptr parsed; - - if (transcode) - { - // New in Orthanc 1.7.0 - std::set syntaxes; - syntaxes.insert(transferSyntax); - - IDicomTranscoder::DicomImage source, transcoded; - source.SetExternalBuffer(content); - - if (context.Transcode(transcoded, source, syntaxes, true /* allow new SOP instance UID */)) - { - writer.Write(transcoded.GetBufferData(), transcoded.GetBufferSize()); - - if (dicomDir != NULL) - { - std::unique_ptr tmp(transcoded.ReleaseAsParsedDicomFile()); - dicomDir->Add(dicomDirFolder, filename_, *tmp); - } - - transcodeSuccess = true; - } - else - { - LOG(INFO) << "Cannot transcode instance " << instanceId_ - << " to transfer syntax: " << GetTransferSyntaxUid(transferSyntax); - } - } - - if (!transcodeSuccess) - { - writer.Write(content); - - if (dicomDir != NULL) - { - if (parsed.get() == NULL) - { - parsed.reset(new ParsedDicomFile(content)); - } - - dicomDir->Add(dicomDirFolder, filename_, *parsed); - } - } - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - }; - - std::deque commands_; - uint64_t uncompressedSize_; - unsigned int instancesCount_; - - - void ApplyInternal(HierarchicalZipWriter& writer, - ServerContext& context, - size_t index, - DicomDirWriter* dicomDir, - const std::string& dicomDirFolder, - bool transcode, - DicomTransferSyntax transferSyntax) const - { - if (index >= commands_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder, transcode, transferSyntax); - } - - public: - ZipCommands() : - uncompressedSize_(0), - instancesCount_(0) - { - } - - ~ZipCommands() - { - for (std::deque::iterator it = commands_.begin(); - it != commands_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - } - - size_t GetSize() const - { - return commands_.size(); - } - - unsigned int GetInstancesCount() const - { - return instancesCount_; - } - - uint64_t GetUncompressedSize() const - { - return uncompressedSize_; - } - - // "media" flavor (with DICOMDIR) - void Apply(HierarchicalZipWriter& writer, - ServerContext& context, - size_t index, - DicomDirWriter& dicomDir, - const std::string& dicomDirFolder, - bool transcode, - DicomTransferSyntax transferSyntax) const - { - ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder, transcode, transferSyntax); - } - - // "archive" flavor (without DICOMDIR) - void Apply(HierarchicalZipWriter& writer, - ServerContext& context, - size_t index, - bool transcode, - DicomTransferSyntax transferSyntax) const - { - ApplyInternal(writer, context, index, NULL, "", transcode, transferSyntax); - } - - void AddOpenDirectory(const std::string& filename) - { - commands_.push_back(new Command(Type_OpenDirectory, filename)); - } - - void AddCloseDirectory() - { - commands_.push_back(new Command(Type_CloseDirectory)); - } - - void AddWriteInstance(const std::string& filename, - const std::string& instanceId, - const FileInfo& info) - { - commands_.push_back(new Command(Type_WriteInstance, filename, instanceId, info)); - instancesCount_ ++; - uncompressedSize_ += info.GetUncompressedSize(); - } - - bool IsZip64() const - { - return IsZip64Required(GetUncompressedSize(), GetInstancesCount()); - } - }; - - - - class ArchiveJob::ArchiveIndexVisitor : public IArchiveVisitor - { - private: - ZipCommands& commands_; - ServerContext& context_; - char instanceFormat_[24]; - unsigned int counter_; - - static std::string GetTag(const DicomMap& tags, - const DicomTag& tag) - { - const DicomValue* v = tags.TestAndGetValue(tag); - if (v != NULL && - !v->IsBinary() && - !v->IsNull()) - { - return v->GetContent(); - } - else - { - return ""; - } - } - - public: - ArchiveIndexVisitor(ZipCommands& commands, - ServerContext& context) : - commands_(commands), - context_(context), - counter_(0) - { - if (commands.GetSize() != 0) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); - } - - virtual void Open(ResourceType level, - const std::string& publicId) - { - std::string path; - - DicomMap tags; - if (context_.GetIndex().GetMainDicomTags(tags, publicId, level, level)) - { - switch (level) - { - case ResourceType_Patient: - path = GetTag(tags, DICOM_TAG_PATIENT_ID) + " " + GetTag(tags, DICOM_TAG_PATIENT_NAME); - break; - - case ResourceType_Study: - path = GetTag(tags, DICOM_TAG_ACCESSION_NUMBER) + " " + GetTag(tags, DICOM_TAG_STUDY_DESCRIPTION); - break; - - case ResourceType_Series: - { - std::string modality = GetTag(tags, DICOM_TAG_MODALITY); - path = modality + " " + GetTag(tags, DICOM_TAG_SERIES_DESCRIPTION); - - if (modality.size() == 0) - { - snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); - } - else if (modality.size() == 1) - { - snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%c%%07d.dcm", - toupper(modality[0])); - } - else if (modality.size() >= 2) - { - snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%c%c%%06d.dcm", - toupper(modality[0]), toupper(modality[1])); - } - - counter_ = 0; - - break; - } - - default: - throw OrthancException(ErrorCode_InternalError); - } - } - - path = Toolbox::StripSpaces(Toolbox::ConvertToAscii(path)); - - if (path.empty()) - { - path = std::string("Unknown ") + EnumerationToString(level); - } - - commands_.AddOpenDirectory(path.c_str()); - } - - virtual void Close() - { - commands_.AddCloseDirectory(); - } - - virtual void AddInstance(const std::string& instanceId, - const FileInfo& dicom) - { - char filename[24]; - snprintf(filename, sizeof(filename) - 1, instanceFormat_, counter_); - counter_ ++; - - commands_.AddWriteInstance(filename, instanceId, dicom); - } - }; - - - class ArchiveJob::MediaIndexVisitor : public IArchiveVisitor - { - private: - ZipCommands& commands_; - ServerContext& context_; - unsigned int counter_; - - public: - MediaIndexVisitor(ZipCommands& commands, - ServerContext& context) : - commands_(commands), - context_(context), - counter_(0) - { - } - - virtual void Open(ResourceType level, - const std::string& publicId) - { - } - - virtual void Close() - { - } - - virtual void AddInstance(const std::string& instanceId, - const FileInfo& dicom) - { - // "DICOM restricts the filenames on DICOM media to 8 - // characters (some systems wrongly use 8.3, but this does not - // conform to the standard)." - std::string filename = "IM" + boost::lexical_cast(counter_); - commands_.AddWriteInstance(filename, instanceId, dicom); - - counter_ ++; - } - }; - - - class ArchiveJob::ZipWriterIterator : public boost::noncopyable - { - private: - TemporaryFile& target_; - ServerContext& context_; - ZipCommands commands_; - std::unique_ptr zip_; - std::unique_ptr dicomDir_; - bool isMedia_; - - public: - ZipWriterIterator(TemporaryFile& target, - ServerContext& context, - ArchiveIndex& archive, - bool isMedia, - bool enableExtendedSopClass) : - target_(target), - context_(context), - isMedia_(isMedia) - { - if (isMedia) - { - MediaIndexVisitor visitor(commands_, context); - archive.Expand(context.GetIndex()); - - commands_.AddOpenDirectory(MEDIA_IMAGES_FOLDER); - archive.Apply(visitor); - commands_.AddCloseDirectory(); - - dicomDir_.reset(new DicomDirWriter); - dicomDir_->EnableExtendedSopClass(enableExtendedSopClass); - } - else - { - ArchiveIndexVisitor visitor(commands_, context); - archive.Expand(context.GetIndex()); - archive.Apply(visitor); - } - - zip_.reset(new HierarchicalZipWriter(target.GetPath().c_str())); - zip_->SetZip64(commands_.IsZip64()); - } - - size_t GetStepsCount() const - { - return commands_.GetSize() + 1; - } - - void RunStep(size_t index, - bool transcode, - DicomTransferSyntax transferSyntax) - { - if (index > commands_.GetSize()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else if (index == commands_.GetSize()) - { - // Last step: Add the DICOMDIR - if (isMedia_) - { - assert(dicomDir_.get() != NULL); - std::string s; - dicomDir_->Encode(s); - - zip_->OpenFile("DICOMDIR"); - zip_->Write(s); - } - } - else - { - if (isMedia_) - { - assert(dicomDir_.get() != NULL); - commands_.Apply(*zip_, context_, index, *dicomDir_, - MEDIA_IMAGES_FOLDER, transcode, transferSyntax); - } - else - { - assert(dicomDir_.get() == NULL); - commands_.Apply(*zip_, context_, index, transcode, transferSyntax); - } - } - } - - unsigned int GetInstancesCount() const - { - return commands_.GetInstancesCount(); - } - - uint64_t GetUncompressedSize() const - { - return commands_.GetUncompressedSize(); - } - }; - - - ArchiveJob::ArchiveJob(ServerContext& context, - bool isMedia, - bool enableExtendedSopClass) : - context_(context), - archive_(new ArchiveIndex(ResourceType_Patient)), // root - isMedia_(isMedia), - enableExtendedSopClass_(enableExtendedSopClass), - currentStep_(0), - instancesCount_(0), - uncompressedSize_(0), - transcode_(false), - transferSyntax_(DicomTransferSyntax_LittleEndianImplicit) - { - } - - - ArchiveJob::~ArchiveJob() - { - if (!mediaArchiveId_.empty()) - { - context_.GetMediaArchive().Remove(mediaArchiveId_); - } - } - - - void ArchiveJob::SetSynchronousTarget(boost::shared_ptr& target) - { - if (target.get() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else if (writer_.get() != NULL || // Already started - synchronousTarget_.get() != NULL || - asynchronousTarget_.get() != NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - synchronousTarget_ = target; - } - } - - - void ArchiveJob::SetDescription(const std::string& description) - { - if (writer_.get() != NULL) // Already started - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - description_ = description; - } - } - - - void ArchiveJob::AddResource(const std::string& publicId) - { - if (writer_.get() != NULL) // Already started - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - ResourceIdentifiers resource(context_.GetIndex(), publicId); - archive_->Add(context_.GetIndex(), resource); - } - } - - - void ArchiveJob::SetTranscode(DicomTransferSyntax transferSyntax) - { - if (writer_.get() != NULL) // Already started - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - transcode_ = true; - transferSyntax_ = transferSyntax; - } - } - - - void ArchiveJob::Reset() - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "Cannot resubmit the creation of an archive"); - } - - - void ArchiveJob::Start() - { - TemporaryFile* target = NULL; - - if (synchronousTarget_.get() == NULL) - { - { - OrthancConfiguration::ReaderLock lock; - asynchronousTarget_.reset(lock.GetConfiguration().CreateTemporaryFile()); - } - - target = asynchronousTarget_.get(); - } - else - { - target = synchronousTarget_.get(); - } - - assert(target != NULL); - target->Touch(); // Make sure we can write to the temporary file - - if (writer_.get() != NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - writer_.reset(new ZipWriterIterator(*target, context_, *archive_, - isMedia_, enableExtendedSopClass_)); - - instancesCount_ = writer_->GetInstancesCount(); - uncompressedSize_ = writer_->GetUncompressedSize(); - } - - - - namespace - { - class DynamicTemporaryFile : public IDynamicObject - { - private: - std::unique_ptr file_; - - public: - DynamicTemporaryFile(TemporaryFile* f) : file_(f) - { - if (f == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - } - - const TemporaryFile& GetFile() const - { - assert(file_.get() != NULL); - return *file_; - } - }; - } - - - void ArchiveJob::FinalizeTarget() - { - writer_.reset(); // Flush all the results - - if (asynchronousTarget_.get() != NULL) - { - // Asynchronous behavior: Move the resulting file into the media archive - mediaArchiveId_ = context_.GetMediaArchive().Add( - new DynamicTemporaryFile(asynchronousTarget_.release())); - } - } - - - JobStepResult ArchiveJob::Step(const std::string& jobId) - { - assert(writer_.get() != NULL); - - if (synchronousTarget_.get() != NULL && - synchronousTarget_.unique()) - { - LOG(WARNING) << "A client has disconnected while creating an archive"; - return JobStepResult::Failure(ErrorCode_NetworkProtocol, - "A client has disconnected while creating an archive"); - } - - if (writer_->GetStepsCount() == 0) - { - FinalizeTarget(); - return JobStepResult::Success(); - } - else - { - writer_->RunStep(currentStep_, transcode_, transferSyntax_); - - currentStep_ ++; - - if (currentStep_ == writer_->GetStepsCount()) - { - FinalizeTarget(); - return JobStepResult::Success(); - } - else - { - return JobStepResult::Continue(); - } - } - } - - - float ArchiveJob::GetProgress() - { - if (writer_.get() == NULL || - writer_->GetStepsCount() == 0) - { - return 1; - } - else - { - return (static_cast(currentStep_) / - static_cast(writer_->GetStepsCount() - 1)); - } - } - - - void ArchiveJob::GetJobType(std::string& target) - { - if (isMedia_) - { - target = "Media"; - } - else - { - target = "Archive"; - } - } - - - void ArchiveJob::GetPublicContent(Json::Value& value) - { - value = Json::objectValue; - value[KEY_DESCRIPTION] = description_; - value[KEY_INSTANCES_COUNT] = instancesCount_; - value[KEY_UNCOMPRESSED_SIZE_MB] = - static_cast(uncompressedSize_ / MEGA_BYTES); - - if (transcode_) - { - value[KEY_TRANSCODE] = GetTransferSyntaxUid(transferSyntax_); - } - } - - - bool ArchiveJob::GetOutput(std::string& output, - MimeType& mime, - const std::string& key) - { - if (key == "archive" && - !mediaArchiveId_.empty()) - { - SharedArchive::Accessor accessor(context_.GetMediaArchive(), mediaArchiveId_); - - if (accessor.IsValid()) - { - const DynamicTemporaryFile& f = dynamic_cast(accessor.GetItem()); - f.GetFile().Read(output); - mime = MimeType_Zip; - return true; - } - else - { - return false; - } - } - else - { - return false; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ArchiveJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,123 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/Compatibility.h" -#include "../../Core/JobsEngine/IJob.h" -#include "../../Core/TemporaryFile.h" - -#include -#include - -namespace Orthanc -{ - class ServerContext; - - class ArchiveJob : public IJob - { - private: - class ArchiveIndex; - class ArchiveIndexVisitor; - class IArchiveVisitor; - class MediaIndexVisitor; - class ResourceIdentifiers; - class ZipCommands; - class ZipWriterIterator; - - boost::shared_ptr synchronousTarget_; - std::unique_ptr asynchronousTarget_; - ServerContext& context_; - boost::shared_ptr archive_; - bool isMedia_; - bool enableExtendedSopClass_; - std::string description_; - - boost::shared_ptr writer_; - size_t currentStep_; - unsigned int instancesCount_; - uint64_t uncompressedSize_; - std::string mediaArchiveId_; - - // New in Orthanc 1.7.0 - bool transcode_; - DicomTransferSyntax transferSyntax_; - - void FinalizeTarget(); - - public: - ArchiveJob(ServerContext& context, - bool isMedia, - bool enableExtendedSopClass); - - virtual ~ArchiveJob(); - - void SetSynchronousTarget(boost::shared_ptr& synchronousTarget); - - void SetDescription(const std::string& description); - - const std::string& GetDescription() const - { - return description_; - } - - void AddResource(const std::string& publicId); - - void SetTranscode(DicomTransferSyntax transferSyntax); - - virtual void Reset() ORTHANC_OVERRIDE; - - virtual void Start() ORTHANC_OVERRIDE; - - virtual JobStepResult Step(const std::string& jobId) ORTHANC_OVERRIDE; - - virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE - { - } - - virtual float GetProgress() ORTHANC_OVERRIDE; - - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE; - - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; - - virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE - { - return false; // Cannot serialize this kind of job - } - - virtual bool GetOutput(std::string& output, - MimeType& mime, - const std::string& key) ORTHANC_OVERRIDE; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,120 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "CleaningInstancesJob.h" - -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - - -namespace Orthanc -{ - bool CleaningInstancesJob::HandleTrailingStep() - { - if (!keepSource_) - { - const size_t n = GetInstancesCount(); - - for (size_t i = 0; i < n; i++) - { - Json::Value tmp; - context_.DeleteResource(tmp, GetInstance(i), ResourceType_Instance); - } - } - - return true; - } - - - void CleaningInstancesJob::SetKeepSource(bool keep) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - keepSource_ = keep; - } - - - static const char* KEEP_SOURCE = "KeepSource"; - - - CleaningInstancesJob::CleaningInstancesJob(ServerContext& context, - const Json::Value& serialized, - bool defaultKeepSource) : - SetOfInstancesJob(serialized), // (*) - context_(context) - { - if (!HasTrailingStep()) - { - // Should have been set by (*) - throw OrthancException(ErrorCode_InternalError); - } - - if (serialized.isMember(KEEP_SOURCE)) - { - keepSource_ = SerializationToolbox::ReadBoolean(serialized, KEEP_SOURCE); - } - else - { - keepSource_ = defaultKeepSource; - } - } - - - bool CleaningInstancesJob::Serialize(Json::Value& target) - { - if (!SetOfInstancesJob::Serialize(target)) - { - return false; - } - else - { - target[KEEP_SOURCE] = keepSource_; - return true; - } - } - - - void CleaningInstancesJob::Start() - { - if (!HasTrailingStep()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "AddTrailingStep() should have been called before submitting the job"); - } - - SetOfInstancesJob::Start(); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/CleaningInstancesJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,79 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/JobsEngine/SetOfInstancesJob.h" - -namespace Orthanc -{ - class ServerContext; - - class CleaningInstancesJob : public SetOfInstancesJob - { - private: - ServerContext& context_; - bool keepSource_; - - protected: - virtual bool HandleTrailingStep(); - - public: - CleaningInstancesJob(ServerContext& context, - bool keepSource) : - context_(context), - keepSource_(keepSource) - { - } - - CleaningInstancesJob(ServerContext& context, - const Json::Value& serialized, - bool defaultKeepSource); - - ServerContext& GetContext() const - { - return context_; - } - - bool IsKeepSource() const - { - return keepSource_; - } - - void SetKeepSource(bool keep); - - virtual bool Serialize(Json::Value& target); - - virtual void Start(); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,309 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "DicomModalityStoreJob.h" - -#include "../../Core/Compatibility.h" -#include "../../Core/DicomNetworking/DicomAssociation.h" -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" -#include "../StorageCommitmentReports.h" - - -namespace Orthanc -{ - void DicomModalityStoreJob::OpenConnection() - { - if (connection_.get() == NULL) - { - connection_.reset(new DicomStoreUserConnection(parameters_)); - } - } - - - bool DicomModalityStoreJob::HandleInstance(const std::string& instance) - { - assert(IsStarted()); - OpenConnection(); - - LOG(INFO) << "Sending instance " << instance << " to modality \"" - << parameters_.GetRemoteModality().GetApplicationEntityTitle() << "\""; - - std::string dicom; - - try - { - context_.ReadDicom(dicom, instance); - } - catch (OrthancException& e) - { - LOG(WARNING) << "An instance was removed after the job was issued: " << instance; - return false; - } - - std::string sopClassUid, sopInstanceUid; - context_.StoreWithTranscoding(sopClassUid, sopInstanceUid, *connection_, dicom, - HasMoveOriginator(), moveOriginatorAet_, moveOriginatorId_); - - if (storageCommitment_) - { - sopClassUids_.push_back(sopClassUid); - sopInstanceUids_.push_back(sopInstanceUid); - - if (sopClassUids_.size() != sopInstanceUids_.size() || - sopClassUids_.size() > GetInstancesCount()) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (sopClassUids_.size() == GetInstancesCount()) - { - assert(IsStarted()); - connection_.reset(NULL); - - const std::string& remoteAet = parameters_.GetRemoteModality().GetApplicationEntityTitle(); - - LOG(INFO) << "Sending storage commitment request to modality: " << remoteAet; - - // Create a "pending" storage commitment report BEFORE the - // actual SCU call in order to avoid race conditions - context_.GetStorageCommitmentReports().Store( - transactionUid_, new StorageCommitmentReports::Report(remoteAet)); - - std::vector a(sopClassUids_.begin(), sopClassUids_.end()); - std::vector b(sopInstanceUids_.begin(), sopInstanceUids_.end()); - - DicomAssociation::RequestStorageCommitment(parameters_, transactionUid_, a, b); - } - } - - //boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - - return true; - } - - - bool DicomModalityStoreJob::HandleTrailingStep() - { - throw OrthancException(ErrorCode_InternalError); - } - - - DicomModalityStoreJob::DicomModalityStoreJob(ServerContext& context) : - context_(context), - moveOriginatorId_(0), // By default, not a C-MOVE - storageCommitment_(false) // By default, no storage commitment - { - ResetStorageCommitment(); - } - - - void DicomModalityStoreJob::SetLocalAet(const std::string& aet) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetLocalApplicationEntityTitle(aet); - } - } - - - void DicomModalityStoreJob::SetRemoteModality(const RemoteModalityParameters& remote) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetRemoteModality(remote); - } - } - - - void DicomModalityStoreJob::SetTimeout(uint32_t seconds) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetTimeout(seconds); - } - } - - - const std::string& DicomModalityStoreJob::GetMoveOriginatorAet() const - { - if (HasMoveOriginator()) - { - return moveOriginatorAet_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - uint16_t DicomModalityStoreJob::GetMoveOriginatorId() const - { - if (HasMoveOriginator()) - { - return moveOriginatorId_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void DicomModalityStoreJob::SetMoveOriginator(const std::string& aet, - int id) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (id < 0 || - id >= 65536) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - moveOriginatorId_ = static_cast(id); - moveOriginatorAet_ = aet; - } - } - - void DicomModalityStoreJob::Stop(JobStopReason reason) // For pausing jobs - { - connection_.reset(NULL); - } - - - void DicomModalityStoreJob::ResetStorageCommitment() - { - if (storageCommitment_) - { - transactionUid_ = Toolbox::GenerateDicomPrivateUniqueIdentifier(); - sopClassUids_.clear(); - sopInstanceUids_.clear(); - } - } - - - void DicomModalityStoreJob::Reset() - { - SetOfInstancesJob::Reset(); - - /** - * "After the N-EVENT-REPORT has been sent, the Transaction UID is - * no longer active and shall not be reused for other - * transactions." => Need to reset the transaction UID here - * http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html - **/ - ResetStorageCommitment(); - } - - - void DicomModalityStoreJob::EnableStorageCommitment(bool enabled) - { - storageCommitment_ = enabled; - ResetStorageCommitment(); - } - - - void DicomModalityStoreJob::GetPublicContent(Json::Value& value) - { - SetOfInstancesJob::GetPublicContent(value); - - value["LocalAet"] = parameters_.GetLocalApplicationEntityTitle(); - value["RemoteAet"] = parameters_.GetRemoteModality().GetApplicationEntityTitle(); - - if (HasMoveOriginator()) - { - value["MoveOriginatorAET"] = GetMoveOriginatorAet(); - value["MoveOriginatorID"] = GetMoveOriginatorId(); - } - - if (storageCommitment_) - { - value["StorageCommitmentTransactionUID"] = transactionUid_; - } - } - - - static const char* MOVE_ORIGINATOR_AET = "MoveOriginatorAet"; - static const char* MOVE_ORIGINATOR_ID = "MoveOriginatorId"; - static const char* STORAGE_COMMITMENT = "StorageCommitment"; - - - DicomModalityStoreJob::DicomModalityStoreJob(ServerContext& context, - const Json::Value& serialized) : - SetOfInstancesJob(serialized), - context_(context) - { - moveOriginatorAet_ = SerializationToolbox::ReadString(serialized, MOVE_ORIGINATOR_AET); - moveOriginatorId_ = static_cast - (SerializationToolbox::ReadUnsignedInteger(serialized, MOVE_ORIGINATOR_ID)); - EnableStorageCommitment(SerializationToolbox::ReadBoolean(serialized, STORAGE_COMMITMENT)); - - parameters_ = DicomAssociationParameters::UnserializeJob(serialized); - } - - - bool DicomModalityStoreJob::Serialize(Json::Value& target) - { - if (!SetOfInstancesJob::Serialize(target)) - { - return false; - } - else - { - parameters_.SerializeJob(target); - target[MOVE_ORIGINATOR_AET] = moveOriginatorAet_; - target[MOVE_ORIGINATOR_ID] = moveOriginatorId_; - target[STORAGE_COMMITMENT] = storageCommitment_; - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomModalityStoreJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,119 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/Compatibility.h" -#include "../../Core/JobsEngine/SetOfInstancesJob.h" -#include "../../Core/DicomNetworking/DicomStoreUserConnection.h" - -#include - -namespace Orthanc -{ - class ServerContext; - - class DicomModalityStoreJob : public SetOfInstancesJob - { - private: - ServerContext& context_; - DicomAssociationParameters parameters_; - std::string moveOriginatorAet_; - uint16_t moveOriginatorId_; - std::unique_ptr connection_; - bool storageCommitment_; - - // For storage commitment - std::string transactionUid_; - std::list sopInstanceUids_; - std::list sopClassUids_; - - void OpenConnection(); - - void ResetStorageCommitment(); - - protected: - virtual bool HandleInstance(const std::string& instance) ORTHANC_OVERRIDE; - - virtual bool HandleTrailingStep() ORTHANC_OVERRIDE; - - public: - DicomModalityStoreJob(ServerContext& context); - - DicomModalityStoreJob(ServerContext& context, - const Json::Value& serialized); - - const DicomAssociationParameters& GetParameters() const - { - return parameters_; - } - - void SetLocalAet(const std::string& aet); - - void SetRemoteModality(const RemoteModalityParameters& remote); - - void SetTimeout(uint32_t seconds); - - bool HasMoveOriginator() const - { - return moveOriginatorId_ != 0; - } - - const std::string& GetMoveOriginatorAet() const; - - uint16_t GetMoveOriginatorId() const; - - void SetMoveOriginator(const std::string& aet, - int id); - - virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; - - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE - { - target = "DicomModalityStore"; - } - - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; - - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; - - virtual void Reset() ORTHANC_OVERRIDE; - - void EnableStorageCommitment(bool enabled); - - bool HasStorageCommitment() const - { - return storageCommitment_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "DicomMoveScuJob.h" - -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - -static const char* const LOCAL_AET = "LocalAet"; -static const char* const TARGET_AET = "TargetAet"; -static const char* const REMOTE = "Remote"; -static const char* const QUERY = "Query"; -static const char* const TIMEOUT = "Timeout"; - -namespace Orthanc -{ - class DicomMoveScuJob::Command : public SetOfCommandsJob::ICommand - { - private: - DicomMoveScuJob& that_; - std::unique_ptr findAnswer_; - - public: - Command(DicomMoveScuJob& that, - const DicomMap& findAnswer) : - that_(that), - findAnswer_(findAnswer.Clone()) - { - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - that_.Retrieve(*findAnswer_); - return true; - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - findAnswer_->Serialize(target); - } - }; - - - class DicomMoveScuJob::Unserializer : - public SetOfCommandsJob::ICommandUnserializer - { - private: - DicomMoveScuJob& that_; - - public: - Unserializer(DicomMoveScuJob& that) : - that_(that) - { - } - - virtual ICommand* Unserialize(const Json::Value& source) const - { - DicomMap findAnswer; - findAnswer.Unserialize(source); - return new Command(that_, findAnswer); - } - }; - - - - void DicomMoveScuJob::Retrieve(const DicomMap& findAnswer) - { - if (connection_.get() == NULL) - { - connection_.reset(new DicomControlUserConnection(parameters_)); - } - - connection_->Move(targetAet_, findAnswer); - } - - - static void AddTagIfString(Json::Value& target, - const DicomMap& answer, - const DicomTag& tag) - { - const DicomValue* value = answer.TestAndGetValue(tag); - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - target[tag.Format()] = value->GetContent(); - } - } - - - void DicomMoveScuJob::AddFindAnswer(const DicomMap& answer) - { - assert(query_.type() == Json::arrayValue); - - // Copy the identifiers tags, if they exist - Json::Value item = Json::objectValue; - AddTagIfString(item, answer, DICOM_TAG_QUERY_RETRIEVE_LEVEL); - AddTagIfString(item, answer, DICOM_TAG_PATIENT_ID); - AddTagIfString(item, answer, DICOM_TAG_STUDY_INSTANCE_UID); - AddTagIfString(item, answer, DICOM_TAG_SERIES_INSTANCE_UID); - AddTagIfString(item, answer, DICOM_TAG_SOP_INSTANCE_UID); - AddTagIfString(item, answer, DICOM_TAG_ACCESSION_NUMBER); - query_.append(item); - - AddCommand(new Command(*this, answer)); - } - - - void DicomMoveScuJob::AddFindAnswer(QueryRetrieveHandler& query, - size_t i) - { - DicomMap answer; - query.GetAnswer(answer, i); - AddFindAnswer(answer); - } - - - void DicomMoveScuJob::SetLocalAet(const std::string& aet) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetLocalApplicationEntityTitle(aet); - } - } - - - void DicomMoveScuJob::SetTargetAet(const std::string& aet) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - targetAet_ = aet; - } - } - - - void DicomMoveScuJob::SetRemoteModality(const RemoteModalityParameters& remote) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetRemoteModality(remote); - } - } - - - void DicomMoveScuJob::SetTimeout(uint32_t seconds) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - parameters_.SetTimeout(seconds); - } - } - - - void DicomMoveScuJob::Stop(JobStopReason reason) - { - connection_.reset(); - } - - - void DicomMoveScuJob::GetPublicContent(Json::Value& value) - { - SetOfCommandsJob::GetPublicContent(value); - - value["LocalAet"] = parameters_.GetLocalApplicationEntityTitle(); - value["RemoteAet"] = parameters_.GetRemoteModality().GetApplicationEntityTitle(); - value["Query"] = query_; - } - - - DicomMoveScuJob::DicomMoveScuJob(ServerContext& context, - const Json::Value& serialized) : - SetOfCommandsJob(new Unserializer(*this), serialized), - context_(context), - query_(Json::arrayValue) - { - parameters_ = DicomAssociationParameters::UnserializeJob(serialized); - targetAet_ = SerializationToolbox::ReadString(serialized, TARGET_AET); - - if (serialized.isMember(QUERY) && - serialized[QUERY].type() == Json::arrayValue) - { - query_ = serialized[QUERY]; - } - } - - - bool DicomMoveScuJob::Serialize(Json::Value& target) - { - if (!SetOfCommandsJob::Serialize(target)) - { - return false; - } - else - { - parameters_.SerializeJob(target); - target[TARGET_AET] = targetAet_; - target[QUERY] = query_; - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/DicomMoveScuJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/Compatibility.h" -#include "../../Core/DicomNetworking/DicomControlUserConnection.h" -#include "../../Core/JobsEngine/SetOfCommandsJob.h" - -#include "../QueryRetrieveHandler.h" - -namespace Orthanc -{ - class ServerContext; - - class DicomMoveScuJob : public SetOfCommandsJob - { - private: - class Command; - class Unserializer; - - ServerContext& context_; - DicomAssociationParameters parameters_; - std::string targetAet_; - Json::Value query_; - - std::unique_ptr connection_; - - void Retrieve(const DicomMap& findAnswer); - - public: - DicomMoveScuJob(ServerContext& context) : - context_(context), - query_(Json::arrayValue) - { - } - - DicomMoveScuJob(ServerContext& context, - const Json::Value& serialized); - - void AddFindAnswer(const DicomMap& answer); - - void AddFindAnswer(QueryRetrieveHandler& query, - size_t i); - - const DicomAssociationParameters& GetParameters() const - { - return parameters_; - } - - void SetLocalAet(const std::string& aet); - - void SetRemoteModality(const RemoteModalityParameters& remote); - - void SetTimeout(uint32_t timeout); - - const std::string& GetTargetAet() const - { - return targetAet_; - } - - void SetTargetAet(const std::string& aet); - - virtual void Stop(JobStopReason reason); - - virtual void GetJobType(std::string& target) - { - target = "DicomMoveScu"; - } - - virtual void GetPublicContent(Json::Value& value); - - virtual bool Serialize(Json::Value& target); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/IStorageCommitmentFactory.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/IStorageCommitmentFactory.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/IStorageCommitmentFactory.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/IStorageCommitmentFactory.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include -#include - -namespace Orthanc -{ - class IStorageCommitmentFactory : public boost::noncopyable - { - public: - class ILookupHandler : public boost::noncopyable - { - public: - virtual ~ILookupHandler() - { - } - - virtual StorageCommitmentFailureReason Lookup(const std::string& sopClassUid, - const std::string& sopInstanceUid) = 0; - }; - - virtual ~IStorageCommitmentFactory() - { - } - - virtual ILookupHandler* CreateStorageCommitment(const std::string& jobId, - const std::string& transactionUid, - const std::vector& sopClassUids, - const std::vector& sopInstanceUids, - const std::string& remoteAet, - const std::string& calledAet) = 0; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "LuaJobManager.h" - -#include "../OrthancConfiguration.h" -#include "../../Core/Logging.h" - -#include "../../Core/JobsEngine/Operations/LogJobOperation.h" -#include "Operations/DeleteResourceOperation.h" -#include "Operations/ModifyInstanceOperation.h" -#include "Operations/StorePeerOperation.h" -#include "Operations/StoreScuOperation.h" -#include "Operations/SystemCallOperation.h" - -#include "../../Core/JobsEngine/Operations/NullOperationValue.h" -#include "../../Core/JobsEngine/Operations/StringOperationValue.h" -#include "Operations/DicomInstanceOperationValue.h" - -namespace Orthanc -{ - void LuaJobManager::SignalDone(const SequenceOfOperationsJob& job) - { - boost::mutex::scoped_lock lock(mutex_); - - if (&job == currentJob_) - { - currentId_.clear(); - currentJob_ = NULL; - } - } - - - LuaJobManager::LuaJobManager() : - currentJob_(NULL), - maxOperations_(1000), - priority_(0), - trailingTimeout_(5000) - { - unsigned int dicomTimeout; - - { - OrthancConfiguration::ReaderLock lock; - dicomTimeout = lock.GetConfiguration().GetUnsignedIntegerParameter("DicomAssociationCloseDelay", 5); - } - - connectionManager_.SetInactivityTimeout(dicomTimeout * 1000); // Milliseconds expected - LOG(INFO) << "Lua: DICOM associations will be closed after " - << dicomTimeout << " seconds of inactivity"; - } - - - void LuaJobManager::SetMaxOperationsPerJob(size_t count) - { - boost::mutex::scoped_lock lock(mutex_); - maxOperations_ = count; - } - - - void LuaJobManager::SetPriority(int priority) - { - boost::mutex::scoped_lock lock(mutex_); - priority_ = priority; - } - - - void LuaJobManager::SetTrailingOperationTimeout(unsigned int timeout) - { - boost::mutex::scoped_lock lock(mutex_); - trailingTimeout_ = timeout; - } - - - void LuaJobManager::AwakeTrailingSleep() - { - boost::mutex::scoped_lock lock(mutex_); - - LOG(INFO) << "Awaking trailing sleep"; - - if (currentJob_ != NULL) - { - currentJob_->AwakeTrailingSleep(); - } - } - - - LuaJobManager::Lock::Lock(LuaJobManager& that, - JobsEngine& engine) : - that_(that), - lock_(that.mutex_), - engine_(engine) - { - if (that_.currentJob_ == NULL) - { - isNewJob_ = true; - } - else - { - jobLock_.reset(new SequenceOfOperationsJob::Lock(*that_.currentJob_)); - - if (jobLock_->IsDone() || - jobLock_->GetOperationsCount() >= that_.maxOperations_) - { - jobLock_.reset(NULL); - isNewJob_ = true; - } - else - { - isNewJob_ = false; - } - } - - if (isNewJob_) - { - // Need to create a new job, as the previous one is either - // finished, or is getting too long - that_.currentJob_ = new SequenceOfOperationsJob; - that_.currentJob_->Register(that_); - that_.currentJob_->SetDescription("Lua"); - - { - jobLock_.reset(new SequenceOfOperationsJob::Lock(*that_.currentJob_)); - jobLock_->SetTrailingOperationTimeout(that_.trailingTimeout_); - } - } - - assert(jobLock_.get() != NULL); - } - - - LuaJobManager::Lock::~Lock() - { - bool isEmpty; - - assert(jobLock_.get() != NULL); - isEmpty = (isNewJob_ && - jobLock_->GetOperationsCount() == 0); - - jobLock_.reset(NULL); - - if (isNewJob_) - { - if (isEmpty) - { - // No operation was added, discard the newly created job - isNewJob_ = false; - delete that_.currentJob_; - that_.currentJob_ = NULL; - } - else - { - engine_.GetRegistry().Submit(that_.currentId_, that_.currentJob_, that_.priority_); - } - } - } - - - size_t LuaJobManager::Lock::AddDeleteResourceOperation(ServerContext& context) - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation(new DeleteResourceOperation(context)); - } - - - size_t LuaJobManager::Lock::AddLogOperation() - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation(new LogJobOperation); - } - - - size_t LuaJobManager::Lock::AddStoreScuOperation(ServerContext& context, - const std::string& localAet, - const RemoteModalityParameters& modality) - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation(new StoreScuOperation( - context, that_.connectionManager_, localAet, modality)); - } - - - size_t LuaJobManager::Lock::AddStorePeerOperation(const WebServiceParameters& peer) - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation(new StorePeerOperation(peer)); - } - - - size_t LuaJobManager::Lock::AddSystemCallOperation(const std::string& command) - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation(new SystemCallOperation(command)); - } - - - size_t LuaJobManager::Lock::AddSystemCallOperation - (const std::string& command, - const std::vector& preArguments, - const std::vector& postArguments) - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation - (new SystemCallOperation(command, preArguments, postArguments)); - } - - - size_t LuaJobManager::Lock::AddModifyInstanceOperation(ServerContext& context, - DicomModification* modification) - { - assert(jobLock_.get() != NULL); - return jobLock_->AddOperation - (new ModifyInstanceOperation(context, RequestOrigin_Lua, modification)); - } - - - void LuaJobManager::Lock::AddNullInput(size_t operation) - { - assert(jobLock_.get() != NULL); - NullOperationValue null; - jobLock_->AddInput(operation, null); - } - - - void LuaJobManager::Lock::AddStringInput(size_t operation, - const std::string& content) - { - assert(jobLock_.get() != NULL); - StringOperationValue value(content); - jobLock_->AddInput(operation, value); - } - - - void LuaJobManager::Lock::AddDicomInstanceInput(size_t operation, - ServerContext& context, - const std::string& instanceId) - { - assert(jobLock_.get() != NULL); - DicomInstanceOperationValue value(context, instanceId); - jobLock_->AddInput(operation, value); - } - - - void LuaJobManager::Lock::Connect(size_t operation1, - size_t operation2) - { - assert(jobLock_.get() != NULL); - jobLock_->Connect(operation1, operation2); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/LuaJobManager.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,122 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomNetworking/TimeoutDicomConnectionManager.h" -#include "../../Core/DicomParsing/DicomModification.h" -#include "../../Core/JobsEngine/JobsEngine.h" -#include "../../Core/JobsEngine/Operations/SequenceOfOperationsJob.h" -#include "../../Core/WebServiceParameters.h" - -namespace Orthanc -{ - class ServerContext; - - class LuaJobManager : private SequenceOfOperationsJob::IObserver - { - private: - boost::mutex mutex_; - std::string currentId_; - SequenceOfOperationsJob* currentJob_; - size_t maxOperations_; - int priority_; - unsigned int trailingTimeout_; - TimeoutDicomConnectionManager connectionManager_; - - virtual void SignalDone(const SequenceOfOperationsJob& job); - - public: - LuaJobManager(); - - void SetMaxOperationsPerJob(size_t count); - - void SetPriority(int priority); - - void SetTrailingOperationTimeout(unsigned int timeout); - - void AwakeTrailingSleep(); - - TimeoutDicomConnectionManager& GetDicomConnectionManager() - { - return connectionManager_; - } - - class Lock : public boost::noncopyable - { - private: - LuaJobManager& that_; - boost::mutex::scoped_lock lock_; - JobsEngine& engine_; - std::unique_ptr jobLock_; - bool isNewJob_; - - public: - Lock(LuaJobManager& that, - JobsEngine& engine); - - ~Lock(); - - size_t AddLogOperation(); - - size_t AddDeleteResourceOperation(ServerContext& context); - - size_t AddStoreScuOperation(ServerContext& context, - const std::string& localAet, - const RemoteModalityParameters& modality); - - size_t AddStorePeerOperation(const WebServiceParameters& peer); - - size_t AddSystemCallOperation(const std::string& command); - - size_t AddSystemCallOperation(const std::string& command, - const std::vector& preArguments, - const std::vector& postArguments); - - size_t AddModifyInstanceOperation(ServerContext& context, - DicomModification* modification); - - void AddNullInput(size_t operation); - - void AddStringInput(size_t operation, - const std::string& content); - - void AddDicomInstanceInput(size_t operation, - ServerContext& context, - const std::string& instanceId); - - void Connect(size_t operation1, - size_t operation2); - }; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,375 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "MergeStudyJob.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - - -namespace Orthanc -{ - void MergeStudyJob::AddSourceSeriesInternal(const std::string& series) - { - // Generate a target SeriesInstanceUID for this series - seriesUidMap_[series] = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series); - - // Add all the instances of the series as to be processed - std::list instances; - GetContext().GetIndex().GetChildren(instances, series); - - for (std::list::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - AddInstance(*it); - } - } - - - void MergeStudyJob::AddSourceStudyInternal(const std::string& study) - { - if (study == targetStudy_) - { - throw OrthancException(ErrorCode_UnknownResource, - "Cannot merge a study into the same study: " + study); - } - else - { - std::list series; - GetContext().GetIndex().GetChildren(series, study); - - for (std::list::const_iterator - it = series.begin(); it != series.end(); ++it) - { - AddSourceSeriesInternal(*it); - } - } - } - - - bool MergeStudyJob::HandleInstance(const std::string& instance) - { - if (!HasTrailingStep()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "AddTrailingStep() should have been called after AddSourceXXX()"); - } - - /** - * Retrieve the DICOM instance to be modified - **/ - - std::unique_ptr modified; - - try - { - ServerContext::DicomCacheLocker locker(GetContext(), instance); - modified.reset(locker.GetDicom().Clone(true)); - } - catch (OrthancException&) - { - LOG(WARNING) << "An instance was removed after the job was issued: " << instance; - return false; - } - - - /** - * Chose the target UIDs - **/ - - std::string series = modified->GetHasher().HashSeries(); - - SeriesUidMap::const_iterator targetSeriesUid = seriesUidMap_.find(series); - - if (targetSeriesUid == seriesUidMap_.end()) - { - throw OrthancException(ErrorCode_BadFileFormat); // Should never happen - } - - - /** - * Copy the tags from the "Patient Module Attributes" and "General - * Study Module Attributes" modules of the target study - **/ - - for (std::set::const_iterator it = removals_.begin(); - it != removals_.end(); ++it) - { - modified->Remove(*it); - } - - for (Replacements::const_iterator it = replacements_.begin(); - it != replacements_.end(); ++it) - { - modified->ReplacePlainString(it->first, it->second); - } - - - /** - * Store the new instance into Orthanc - **/ - - modified->ReplacePlainString(DICOM_TAG_SERIES_INSTANCE_UID, targetSeriesUid->second); - - // Fix since Orthanc 1.5.8: Assign new "SOPInstanceUID", as the instance has been modified - modified->ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance)); - - DicomInstanceToStore toStore; - toStore.SetOrigin(origin_); - toStore.SetParsedDicomFile(*modified); - - std::string modifiedInstance; - if (GetContext().Store(modifiedInstance, toStore, - StoreInstanceMode_Default) != StoreStatus_Success) - { - LOG(ERROR) << "Error while storing a modified instance " << instance; - return false; - } - - return true; - } - - - MergeStudyJob::MergeStudyJob(ServerContext& context, - const std::string& targetStudy) : - CleaningInstancesJob(context, false /* by default, remove source instances */), - targetStudy_(targetStudy) - { - /** - * Check the validity of the input ID - **/ - - ResourceType type; - - if (!GetContext().GetIndex().LookupResourceType(type, targetStudy) || - type != ResourceType_Study) - { - throw OrthancException(ErrorCode_UnknownResource, - "Cannot merge into an unknown study: " + targetStudy); - } - - - /** - * Detect the tags to be removed/replaced by parsing one child - * instance of the study - **/ - - DicomTag::AddTagsForModule(removals_, DicomModule_Patient); - DicomTag::AddTagsForModule(removals_, DicomModule_Study); - - std::list instances; - GetContext().GetIndex().GetChildInstances(instances, targetStudy); - - if (instances.empty()) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - DicomMap dicom; - - { - ServerContext::DicomCacheLocker locker(GetContext(), instances.front()); - locker.GetDicom().ExtractDicomSummary(dicom); - } - - const std::set moduleTags = removals_; - for (std::set::const_iterator it = moduleTags.begin(); - it != moduleTags.end(); ++it) - { - const DicomValue* value = dicom.TestAndGetValue(*it); - std::string str; - - if (value != NULL && - value->CopyToString(str, false)) - { - removals_.erase(*it); - replacements_.insert(std::make_pair(*it, str)); - } - } - } - - - void MergeStudyJob::SetOrigin(const DicomInstanceOrigin& origin) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - origin_ = origin; - } - } - - - void MergeStudyJob::SetOrigin(const RestApiCall& call) - { - SetOrigin(DicomInstanceOrigin::FromRest(call)); - } - - - void MergeStudyJob::AddSource(const std::string& studyOrSeries) - { - ResourceType level; - - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (!GetContext().GetIndex().LookupResourceType(level, studyOrSeries)) - { - throw OrthancException(ErrorCode_UnknownResource, - "Cannot find this resource: " + studyOrSeries); - } - else - { - switch (level) - { - case ResourceType_Study: - AddSourceStudyInternal(studyOrSeries); - break; - - case ResourceType_Series: - AddSourceSeries(studyOrSeries); - break; - - default: - throw OrthancException(ErrorCode_UnknownResource, - "This resource is neither a study, nor a series: " + - studyOrSeries + " is a " + - std::string(EnumerationToString(level))); - } - } - } - - - void MergeStudyJob::AddSourceSeries(const std::string& series) - { - std::string parent; - - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (!GetContext().GetIndex().LookupParent(parent, series, ResourceType_Study)) - { - throw OrthancException(ErrorCode_UnknownResource, - "This resource is not a series: " + series); - } - else if (parent == targetStudy_) - { - throw OrthancException(ErrorCode_UnknownResource, - "Cannot merge series " + series + - " into its parent study " + targetStudy_); - } - else - { - AddSourceSeriesInternal(series); - } - } - - - void MergeStudyJob::AddSourceStudy(const std::string& study) - { - ResourceType actualLevel; - - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (!GetContext().GetIndex().LookupResourceType(actualLevel, study) || - actualLevel != ResourceType_Study) - { - throw OrthancException(ErrorCode_UnknownResource, - "This resource is not a study: " + study); - } - else - { - AddSourceStudyInternal(study); - } - } - - - void MergeStudyJob::GetPublicContent(Json::Value& value) - { - CleaningInstancesJob::GetPublicContent(value); - value["TargetStudy"] = targetStudy_; - } - - - static const char* TARGET_STUDY = "TargetStudy"; - static const char* REPLACEMENTS = "Replacements"; - static const char* REMOVALS = "Removals"; - static const char* SERIES_UID_MAP = "SeriesUIDMap"; - static const char* ORIGIN = "Origin"; - - - MergeStudyJob::MergeStudyJob(ServerContext& context, - const Json::Value& serialized) : - CleaningInstancesJob(context, serialized, - false /* by default, remove source instances */) // (*) - { - if (!HasTrailingStep()) - { - // Should have been set by (*) - throw OrthancException(ErrorCode_InternalError); - } - - targetStudy_ = SerializationToolbox::ReadString(serialized, TARGET_STUDY); - SerializationToolbox::ReadMapOfTags(replacements_, serialized, REPLACEMENTS); - SerializationToolbox::ReadSetOfTags(removals_, serialized, REMOVALS); - SerializationToolbox::ReadMapOfStrings(seriesUidMap_, serialized, SERIES_UID_MAP); - origin_ = DicomInstanceOrigin(serialized[ORIGIN]); - } - - - bool MergeStudyJob::Serialize(Json::Value& target) - { - if (!CleaningInstancesJob::Serialize(target)) - { - return false; - } - else - { - target[TARGET_STUDY] = targetStudy_; - SerializationToolbox::WriteMapOfTags(target, replacements_, REPLACEMENTS); - SerializationToolbox::WriteSetOfTags(target, removals_, REMOVALS); - SerializationToolbox::WriteMapOfStrings(target, seriesUidMap_, SERIES_UID_MAP); - origin_.Serialize(target[ORIGIN]); - - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/MergeStudyJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomFormat/DicomMap.h" -#include "../DicomInstanceOrigin.h" -#include "CleaningInstancesJob.h" - -namespace Orthanc -{ - class ServerContext; - - class MergeStudyJob : public CleaningInstancesJob - { - private: - typedef std::map SeriesUidMap; - typedef std::map Replacements; - - - std::string targetStudy_; - Replacements replacements_; - std::set removals_; - SeriesUidMap seriesUidMap_; - DicomInstanceOrigin origin_; - - - void AddSourceSeriesInternal(const std::string& series); - - void AddSourceStudyInternal(const std::string& study); - - protected: - virtual bool HandleInstance(const std::string& instance); - - public: - MergeStudyJob(ServerContext& context, - const std::string& targetStudy); - - MergeStudyJob(ServerContext& context, - const Json::Value& serialized); - - const std::string& GetTargetStudy() const - { - return targetStudy_; - } - - void AddSource(const std::string& studyOrSeries); - - void AddSourceStudy(const std::string& study); - - void AddSourceSeries(const std::string& series); - - void SetOrigin(const DicomInstanceOrigin& origin); - - void SetOrigin(const RestApiCall& call); - - const DicomInstanceOrigin& GetOrigin() const - { - return origin_; - } - - virtual void Stop(JobStopReason reason) - { - } - - virtual void GetJobType(std::string& target) - { - target = "MergeStudy"; - } - - virtual void GetPublicContent(Json::Value& value); - - virtual bool Serialize(Json::Value& target); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "DeleteResourceOperation.h" - -#include "DicomInstanceOperationValue.h" -#include "../../ServerContext.h" - -#include "../../../Core/Logging.h" -#include "../../../Core/OrthancException.h" - -namespace Orthanc -{ - void DeleteResourceOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input) - { - switch (input.GetType()) - { - case JobOperationValue::Type_DicomInstance: - { - const DicomInstanceOperationValue& instance = dynamic_cast(input); - LOG(INFO) << "Lua: Deleting instance: " << instance.GetId(); - - try - { - Json::Value tmp; - context_.DeleteResource(tmp, instance.GetId(), ResourceType_Instance); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: Unable to delete instance " << instance.GetId() << ": " << e.What(); - } - - break; - } - - default: - break; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/JobsEngine/Operations/IJobOperation.h" - -namespace Orthanc -{ - class ServerContext; - - class DeleteResourceOperation : public IJobOperation - { - private: - ServerContext& context_; - - public: - DeleteResourceOperation(ServerContext& context) : - context_(context) - { - } - - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input); - - virtual void Serialize(Json::Value& result) const - { - result = Json::objectValue; - result["Type"] = "DeleteResource"; - } - }; -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "DicomInstanceOperationValue.h" - -#include "../../ServerContext.h" - -namespace Orthanc -{ - void DicomInstanceOperationValue::ReadDicom(std::string& dicom) const - { - context_.ReadDicom(dicom, id_); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/JobsEngine/Operations/JobOperationValue.h" - -namespace Orthanc -{ - class ServerContext; - - class DicomInstanceOperationValue : public JobOperationValue - { - private: - ServerContext& context_; - std::string id_; - - public: - DicomInstanceOperationValue(ServerContext& context, - const std::string& id) : - JobOperationValue(Type_DicomInstance), - context_(context), - id_(id) - { - } - - ServerContext& GetServerContext() const - { - return context_; - } - - const std::string& GetId() const - { - return id_; - } - - void ReadDicom(std::string& dicom) const; - - virtual JobOperationValue* Clone() const - { - return new DicomInstanceOperationValue(context_, id_); - } - - virtual void Serialize(Json::Value& target) const - { - target = Json::objectValue; - target["Type"] = "DicomInstance"; - target["ID"] = id_; - } - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,153 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "ModifyInstanceOperation.h" - -#include "DicomInstanceOperationValue.h" -#include "../../ServerContext.h" - -#include "../../../Core/Logging.h" -#include "../../../Core/SerializationToolbox.h" - -namespace Orthanc -{ - ModifyInstanceOperation::ModifyInstanceOperation(ServerContext& context, - RequestOrigin origin, - DicomModification* modification) : - context_(context), - origin_(origin), - modification_(modification) - { - if (modification == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - - modification_->SetAllowManualIdentifiers(true); - - if (modification_->IsReplaced(DICOM_TAG_PATIENT_ID)) - { - modification_->SetLevel(ResourceType_Patient); - } - else if (modification_->IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - modification_->SetLevel(ResourceType_Study); - } - else if (modification_->IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - modification_->SetLevel(ResourceType_Series); - } - else - { - modification_->SetLevel(ResourceType_Instance); - } - - if (origin_ != RequestOrigin_Lua) - { - // TODO If issued from HTTP, "remoteIp" and "username" must be provided - throw OrthancException(ErrorCode_NotImplemented); - } - } - - void ModifyInstanceOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input) - { - if (input.GetType() != JobOperationValue::Type_DicomInstance) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - const DicomInstanceOperationValue& instance = - dynamic_cast(input); - - LOG(INFO) << "Lua: Modifying instance " << instance.GetId(); - - std::unique_ptr modified; - - { - ServerContext::DicomCacheLocker lock(context_, instance.GetId()); - modified.reset(lock.GetDicom().Clone(true)); - } - - try - { - modification_->Apply(*modified); - - DicomInstanceToStore toStore; - assert(origin_ == RequestOrigin_Lua); - toStore.SetOrigin(DicomInstanceOrigin::FromLua()); - toStore.SetParsedDicomFile(*modified); - - // TODO other metadata - toStore.AddMetadata(ResourceType_Instance, MetadataType_ModifiedFrom, instance.GetId()); - - std::string modifiedId; - context_.Store(modifiedId, toStore, StoreInstanceMode_Default); - - // Only chain with other commands if this command succeeds - outputs.Append(new DicomInstanceOperationValue(instance.GetServerContext(), modifiedId)); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: Unable to modify instance " << instance.GetId() - << ": " << e.What(); - } - } - - - void ModifyInstanceOperation::Serialize(Json::Value& target) const - { - target = Json::objectValue; - target["Type"] = "ModifyInstance"; - target["Origin"] = EnumerationToString(origin_); - modification_->Serialize(target["Modification"]); - } - - - ModifyInstanceOperation::ModifyInstanceOperation(ServerContext& context, - const Json::Value& serialized) : - context_(context) - { - if (SerializationToolbox::ReadString(serialized, "Type") != "ModifyInstance" || - !serialized.isMember("Modification")) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - origin_ = StringToRequestOrigin(SerializationToolbox::ReadString(serialized, "Origin")); - - modification_.reset(new DicomModification(serialized["Modification"])); - } -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/Compatibility.h" -#include "../../../Core/DicomParsing/DicomModification.h" -#include "../../../Core/JobsEngine/Operations/IJobOperation.h" - -namespace Orthanc -{ - class ServerContext; - - class ModifyInstanceOperation : public IJobOperation - { - private: - ServerContext& context_; - RequestOrigin origin_; - std::unique_ptr modification_; - - public: - ModifyInstanceOperation(ServerContext& context, - RequestOrigin origin, - DicomModification* modification); // Takes ownership - - ModifyInstanceOperation(ServerContext& context, - const Json::Value& serialized); - - const RequestOrigin& GetRequestOrigin() const - { - return origin_; - } - - const DicomModification& GetModification() const - { - return *modification_; - } - - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input); - - virtual void Serialize(Json::Value& target) const; - }; -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "StorePeerOperation.h" - -#include "DicomInstanceOperationValue.h" - -#include "../../../Core/Logging.h" -#include "../../../Core/OrthancException.h" -#include "../../../Core/HttpClient.h" -#include "../../../Core/SerializationToolbox.h" - -namespace Orthanc -{ - void StorePeerOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input) - { - // Configure the HTTP client - HttpClient client(peer_, "instances"); - client.SetMethod(HttpMethod_Post); - - if (input.GetType() != JobOperationValue::Type_DicomInstance) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - const DicomInstanceOperationValue& instance = - dynamic_cast(input); - - LOG(INFO) << "Lua: Sending instance " << instance.GetId() << " to Orthanc peer \"" - << peer_.GetUrl() << "\""; - - try - { - instance.ReadDicom(client.GetBody()); - - std::string answer; - if (!client.Apply(answer)) - { - LOG(ERROR) << "Lua: Unable to send instance " << instance.GetId() - << " to Orthanc peer \"" << peer_.GetUrl(); - } - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: Unable to send instance " << instance.GetId() - << " to Orthanc peer \"" << peer_.GetUrl() << "\": " << e.What(); - } - - outputs.Append(input.Clone()); - } - - - void StorePeerOperation::Serialize(Json::Value& result) const - { - result = Json::objectValue; - result["Type"] = "StorePeer"; - peer_.Serialize(result["Peer"], - true /* force advanced format */, - true /* include passwords */); - } - - - StorePeerOperation::StorePeerOperation(const Json::Value& serialized) - { - if (SerializationToolbox::ReadString(serialized, "Type") != "StorePeer" || - !serialized.isMember("Peer")) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - peer_ = WebServiceParameters(serialized["Peer"]); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StorePeerOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/JobsEngine/Operations/IJobOperation.h" -#include "../../../Core/WebServiceParameters.h" - -namespace Orthanc -{ - class StorePeerOperation : public IJobOperation - { - private: - WebServiceParameters peer_; - - public: - StorePeerOperation(const WebServiceParameters& peer) : - peer_(peer) - { - } - - StorePeerOperation(const Json::Value& serialized); - - const WebServiceParameters& GetPeer() const - { - return peer_; - } - - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input); - - virtual void Serialize(Json::Value& result) const; - }; -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "StoreScuOperation.h" - -#include "DicomInstanceOperationValue.h" -#include "../../ServerContext.h" - -#include "../../../Core/Logging.h" -#include "../../../Core/OrthancException.h" -#include "../../../Core/SerializationToolbox.h" - -namespace Orthanc -{ - void StoreScuOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input) - { - TimeoutDicomConnectionManager::Lock lock(connectionManager_, localAet_, modality_); - - if (input.GetType() != JobOperationValue::Type_DicomInstance) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - const DicomInstanceOperationValue& instance = - dynamic_cast(input); - - LOG(INFO) << "Lua: Sending instance " << instance.GetId() << " to modality \"" - << modality_.GetApplicationEntityTitle() << "\""; - - try - { - std::string dicom; - instance.ReadDicom(dicom); - - std::string sopClassUid, sopInstanceUid; // Unused - context_.StoreWithTranscoding(sopClassUid, sopInstanceUid, lock.GetConnection(), dicom, - false /* Not a C-MOVE */, "", 0); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: Unable to send instance " << instance.GetId() << " to modality \"" - << modality_.GetApplicationEntityTitle() << "\": " << e.What(); - } - - outputs.Append(input.Clone()); - } - - - void StoreScuOperation::Serialize(Json::Value& result) const - { - result = Json::objectValue; - result["Type"] = "StoreScu"; - result["LocalAET"] = localAet_; - modality_.Serialize(result["Modality"], true /* force advanced format */); - } - - - StoreScuOperation::StoreScuOperation(ServerContext& context, - TimeoutDicomConnectionManager& connectionManager, - const Json::Value& serialized) : - context_(context), - connectionManager_(connectionManager) - { - if (SerializationToolbox::ReadString(serialized, "Type") != "StoreScu" || - !serialized.isMember("LocalAET")) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - localAet_ = SerializationToolbox::ReadString(serialized, "LocalAET"); - modality_ = RemoteModalityParameters(serialized["Modality"]); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/StoreScuOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/JobsEngine/Operations/IJobOperation.h" -#include "../../../Core/DicomNetworking/TimeoutDicomConnectionManager.h" - -namespace Orthanc -{ - class ServerContext; - - class StoreScuOperation : public IJobOperation - { - private: - ServerContext& context_; - TimeoutDicomConnectionManager& connectionManager_; - std::string localAet_; - RemoteModalityParameters modality_; - - public: - StoreScuOperation(ServerContext& context, - TimeoutDicomConnectionManager& connectionManager, - const std::string& localAet, - const RemoteModalityParameters& modality) : - context_(context), - connectionManager_(connectionManager), - localAet_(localAet), - modality_(modality) - { - } - - StoreScuOperation(ServerContext& context, - TimeoutDicomConnectionManager& connectionManager, - const Json::Value& serialized); - - const std::string& GetLocalAet() const - { - return localAet_; - } - - const RemoteModalityParameters& GetRemoteModality() const - { - return modality_; - } - - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input); - - virtual void Serialize(Json::Value& result) const; - }; -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,170 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../../PrecompiledHeadersServer.h" -#include "SystemCallOperation.h" - -#include "DicomInstanceOperationValue.h" - -#include "../../../Core/JobsEngine/Operations/StringOperationValue.h" -#include "../../../Core/Logging.h" -#include "../../../Core/OrthancException.h" -#include "../../../Core/SerializationToolbox.h" -#include "../../../Core/TemporaryFile.h" -#include "../../../Core/Toolbox.h" -#include "../../../Core/SystemToolbox.h" -#include "../../OrthancConfiguration.h" - -namespace Orthanc -{ - const std::string& SystemCallOperation::GetPreArgument(size_t i) const - { - if (i >= preArguments_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return preArguments_[i]; - } - } - - - const std::string& SystemCallOperation::GetPostArgument(size_t i) const - { - if (i >= postArguments_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return postArguments_[i]; - } - } - - - void SystemCallOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input) - { - std::vector arguments = preArguments_; - - arguments.reserve(arguments.size() + postArguments_.size() + 1); - - std::unique_ptr tmp; - - switch (input.GetType()) - { - case JobOperationValue::Type_DicomInstance: - { - const DicomInstanceOperationValue& instance = - dynamic_cast(input); - - std::string dicom; - instance.ReadDicom(dicom); - - { - OrthancConfiguration::ReaderLock lock; - tmp.reset(lock.GetConfiguration().CreateTemporaryFile()); - } - - tmp->Write(dicom); - - arguments.push_back(tmp->GetPath()); - break; - } - - case JobOperationValue::Type_String: - { - const StringOperationValue& value = - dynamic_cast(input); - - arguments.push_back(value.GetContent()); - break; - } - - case JobOperationValue::Type_Null: - break; - - default: - throw OrthancException(ErrorCode_BadParameterType); - } - - for (size_t i = 0; i < postArguments_.size(); i++) - { - arguments.push_back(postArguments_[i]); - } - - std::string info = command_; - for (size_t i = 0; i < arguments.size(); i++) - { - info += " " + arguments[i]; - } - - LOG(INFO) << "Lua: System call: \"" << info << "\""; - - try - { - SystemToolbox::ExecuteSystemCommand(command_, arguments); - - // Only chain with other commands if this operation succeeds - outputs.Append(input.Clone()); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Lua: Failed system call - \"" << info << "\": " << e.What(); - } - } - - - void SystemCallOperation::Serialize(Json::Value& result) const - { - result = Json::objectValue; - result["Type"] = "SystemCall"; - result["Command"] = command_; - SerializationToolbox::WriteArrayOfStrings(result, preArguments_, "PreArguments"); - SerializationToolbox::WriteArrayOfStrings(result, postArguments_, "PostArguments"); - } - - - SystemCallOperation::SystemCallOperation(const Json::Value& serialized) - { - if (SerializationToolbox::ReadString(serialized, "Type") != "SystemCall") - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - command_ = SerializationToolbox::ReadString(serialized, "Command"); - SerializationToolbox::ReadArrayOfStrings(preArguments_, serialized, "PreArguments"); - SerializationToolbox::ReadArrayOfStrings(postArguments_, serialized, "PostArguments"); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/Operations/SystemCallOperation.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../../Core/JobsEngine/Operations/IJobOperation.h" - -#include - -namespace Orthanc -{ - class SystemCallOperation : public IJobOperation - { - private: - std::string command_; - std::vector preArguments_; - std::vector postArguments_; - - public: - SystemCallOperation(const std::string& command) : - command_(command) - { - } - - SystemCallOperation(const Json::Value& serialized); - - SystemCallOperation(const std::string& command, - const std::vector& preArguments, - const std::vector& postArguments) : - command_(command), - preArguments_(preArguments), - postArguments_(postArguments) - { - } - - void AddPreArgument(const std::string& argument) - { - preArguments_.push_back(argument); - } - - void AddPostArgument(const std::string& argument) - { - postArguments_.push_back(argument); - } - - const std::string& GetCommand() const - { - return command_; - } - - size_t GetPreArgumentsCount() const - { - return preArguments_.size(); - } - - size_t GetPostArgumentsCount() const - { - return postArguments_.size(); - } - - const std::string& GetPreArgument(size_t i) const; - - const std::string& GetPostArgument(size_t i) const; - - virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input); - - virtual void Serialize(Json::Value& result) const; - }; -} - diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,156 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancJobUnserializer.h" - -#include "../../Core/Logging.h" -#include "../../Core/OrthancException.h" -#include "../../Core/SerializationToolbox.h" -#include "../../Plugins/Engine/OrthancPlugins.h" -#include "../ServerContext.h" - -#include "Operations/DeleteResourceOperation.h" -#include "Operations/DicomInstanceOperationValue.h" -#include "Operations/ModifyInstanceOperation.h" -#include "Operations/StorePeerOperation.h" -#include "Operations/StoreScuOperation.h" -#include "Operations/SystemCallOperation.h" - -#include "DicomModalityStoreJob.h" -#include "DicomMoveScuJob.h" -#include "MergeStudyJob.h" -#include "OrthancPeerStoreJob.h" -#include "ResourceModificationJob.h" -#include "SplitStudyJob.h" -#include "StorageCommitmentScpJob.h" - - -namespace Orthanc -{ - IJob* OrthancJobUnserializer::UnserializeJob(const Json::Value& source) - { - const std::string type = SerializationToolbox::ReadString(source, "Type"); - -#if ORTHANC_ENABLE_PLUGINS == 1 - if (context_.HasPlugins()) - { - std::unique_ptr job(context_.GetPlugins().UnserializeJob(type, source)); - if (job.get() != NULL) - { - return job.release(); - } - } -#endif - - if (type == "DicomModalityStore") - { - return new DicomModalityStoreJob(context_, source); - } - else if (type == "OrthancPeerStore") - { - return new OrthancPeerStoreJob(context_, source); - } - else if (type == "ResourceModification") - { - return new ResourceModificationJob(context_, source); - } - else if (type == "MergeStudy") - { - return new MergeStudyJob(context_, source); - } - else if (type == "SplitStudy") - { - return new SplitStudyJob(context_, source); - } - else if (type == "DicomMoveScu") - { - return new DicomMoveScuJob(context_, source); - } - else if (type == "StorageCommitmentScp") - { - return new StorageCommitmentScpJob(context_, source); - } - else - { - return GenericJobUnserializer::UnserializeJob(source); - } - } - - - IJobOperation* OrthancJobUnserializer::UnserializeOperation(const Json::Value& source) - { - const std::string type = SerializationToolbox::ReadString(source, "Type"); - - if (type == "DeleteResource") - { - return new DeleteResourceOperation(context_); - } - else if (type == "ModifyInstance") - { - return new ModifyInstanceOperation(context_, source); - } - else if (type == "StorePeer") - { - return new StorePeerOperation(source); - } - else if (type == "StoreScu") - { - return new StoreScuOperation( - context_, context_.GetLuaScripting().GetDicomConnectionManager(), source); - } - else if (type == "SystemCall") - { - return new SystemCallOperation(source); - } - else - { - return GenericJobUnserializer::UnserializeOperation(source); - } - } - - - JobOperationValue* OrthancJobUnserializer::UnserializeValue(const Json::Value& source) - { - const std::string type = SerializationToolbox::ReadString(source, "Type"); - - if (type == "DicomInstance") - { - return new DicomInstanceOperationValue(context_, SerializationToolbox::ReadString(source, "ID")); - } - else - { - return GenericJobUnserializer::UnserializeValue(source); - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancJobUnserializer.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,59 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/JobsEngine/GenericJobUnserializer.h" - -namespace Orthanc -{ - class ServerContext; - - class OrthancJobUnserializer : public GenericJobUnserializer - { - private: - ServerContext& context_; - - public: - OrthancJobUnserializer(ServerContext& context) : - context_(context) - { - } - - virtual IJob* UnserializeJob(const Json::Value& value); - - virtual IJobOperation* UnserializeOperation(const Json::Value& value); - - virtual JobOperationValue* UnserializeValue(const Json::Value& value); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,245 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "OrthancPeerStoreJob.h" - -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - -#include - - -namespace Orthanc -{ - bool OrthancPeerStoreJob::HandleInstance(const std::string& instance) - { - //boost::this_thread::sleep(boost::posix_time::milliseconds(500)); - - if (client_.get() == NULL) - { - client_.reset(new HttpClient(peer_, "instances")); - client_->SetMethod(HttpMethod_Post); - } - - LOG(INFO) << "Sending instance " << instance << " to peer \"" - << peer_.GetUrl() << "\""; - - try - { - if (transcode_) - { - std::string dicom; - context_.ReadDicom(dicom, instance); - - std::set syntaxes; - syntaxes.insert(transferSyntax_); - - IDicomTranscoder::DicomImage source, transcoded; - source.SetExternalBuffer(dicom); - - if (context_.Transcode(transcoded, source, syntaxes, true)) - { - client_->GetBody().assign(reinterpret_cast(transcoded.GetBufferData()), - transcoded.GetBufferSize()); - } - else - { - client_->GetBody().swap(dicom); - } - } - else - { - context_.ReadDicom(client_->GetBody(), instance); - } - } - catch (OrthancException& e) - { - LOG(WARNING) << "An instance was removed after the job was issued: " << instance; - return false; - } - - std::string answer; - if (client_->Apply(answer)) - { - return true; - } - else - { - throw OrthancException(ErrorCode_NetworkProtocol); - } - } - - - bool OrthancPeerStoreJob::HandleTrailingStep() - { - throw OrthancException(ErrorCode_InternalError); - } - - - void OrthancPeerStoreJob::SetPeer(const WebServiceParameters& peer) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - peer_ = peer; - } - } - - - DicomTransferSyntax OrthancPeerStoreJob::GetTransferSyntax() const - { - if (transcode_) - { - return transferSyntax_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void OrthancPeerStoreJob::SetTranscode(DicomTransferSyntax syntax) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - transcode_ = true; - transferSyntax_ = syntax; - } - } - - - void OrthancPeerStoreJob::SetTranscode(const std::string& transferSyntaxUid) - { - DicomTransferSyntax s; - if (LookupTransferSyntax(s, transferSyntaxUid)) - { - SetTranscode(s); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Unknown transfer syntax UID: " + transferSyntaxUid); - } - } - - - void OrthancPeerStoreJob::ClearTranscode() - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - transcode_ = false; - } - } - - - void OrthancPeerStoreJob::Stop(JobStopReason reason) // For pausing jobs - { - client_.reset(NULL); - } - - - void OrthancPeerStoreJob::GetPublicContent(Json::Value& value) - { - SetOfInstancesJob::GetPublicContent(value); - - Json::Value v; - peer_.Serialize(v, - false /* allow simple format if possible */, - false /* don't include passwords */); - value["Peer"] = v; - - if (transcode_) - { - value["Transcode"] = GetTransferSyntaxUid(transferSyntax_); - } - } - - - static const char* PEER = "Peer"; - static const char* TRANSCODE = "Transcode"; - - OrthancPeerStoreJob::OrthancPeerStoreJob(ServerContext& context, - const Json::Value& serialized) : - SetOfInstancesJob(serialized), - context_(context) - { - assert(serialized.type() == Json::objectValue); - peer_ = WebServiceParameters(serialized[PEER]); - - if (serialized.isMember(TRANSCODE)) - { - SetTranscode(SerializationToolbox::ReadString(serialized, TRANSCODE)); - } - else - { - transcode_ = false; - } - } - - - bool OrthancPeerStoreJob::Serialize(Json::Value& target) - { - if (!SetOfInstancesJob::Serialize(target)) - { - return false; - } - else - { - assert(target.type() == Json::objectValue); - peer_.Serialize(target[PEER], - true /* force advanced format */, - true /* include passwords */); - - if (transcode_) - { - target[TRANSCODE] = GetTransferSyntaxUid(transferSyntax_); - } - - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/OrthancPeerStoreJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,100 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/Compatibility.h" -#include "../../Core/JobsEngine/SetOfInstancesJob.h" -#include "../../Core/HttpClient.h" - - -namespace Orthanc -{ - class ServerContext; - - class OrthancPeerStoreJob : public SetOfInstancesJob - { - private: - ServerContext& context_; - WebServiceParameters peer_; - std::unique_ptr client_; - bool transcode_; - DicomTransferSyntax transferSyntax_; - - protected: - virtual bool HandleInstance(const std::string& instance); - - virtual bool HandleTrailingStep(); - - public: - OrthancPeerStoreJob(ServerContext& context) : - context_(context), - transcode_(false) - { - } - - OrthancPeerStoreJob(ServerContext& context, - const Json::Value& serialize); - - void SetPeer(const WebServiceParameters& peer); - - const WebServiceParameters& GetPeer() const - { - return peer_; - } - - bool IsTranscode() const - { - return transcode_; - } - - DicomTransferSyntax GetTransferSyntax() const; - - void SetTranscode(DicomTransferSyntax syntax); - - void SetTranscode(const std::string& transferSyntaxUid); - - void ClearTranscode(); - - virtual void Stop(JobStopReason reason); // For pausing jobs - - virtual void GetJobType(std::string& target) - { - target = "OrthancPeerStore"; - } - - virtual void GetPublicContent(Json::Value& value); - - virtual bool Serialize(Json::Value& target); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,460 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "ResourceModificationJob.h" - -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - -#include -#include -#include - -namespace Orthanc -{ - class ResourceModificationJob::Output : public boost::noncopyable - { - private: - ResourceType level_; - bool isFirst_; - std::string id_; - std::string patientId_; - - public: - Output(ResourceType level) : - level_(level), - isFirst_(true) - { - if (level_ != ResourceType_Patient && - level_ != ResourceType_Study && - level_ != ResourceType_Series) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - ResourceType GetLevel() const - { - return level_; - } - - - void Update(DicomInstanceHasher& hasher) - { - if (isFirst_) - { - switch (level_) - { - case ResourceType_Series: - id_ = hasher.HashSeries(); - break; - - case ResourceType_Study: - id_ = hasher.HashStudy(); - break; - - case ResourceType_Patient: - id_ = hasher.HashPatient(); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - patientId_ = hasher.HashPatient(); - isFirst_ = false; - } - } - - - bool Format(Json::Value& target) - { - if (isFirst_) - { - return false; - } - else - { - target = Json::objectValue; - target["Type"] = EnumerationToString(level_); - target["ID"] = id_; - target["Path"] = GetBasePath(level_, id_); - target["PatientID"] = patientId_; - return true; - } - } - - - bool GetIdentifier(std::string& id) - { - if (isFirst_) - { - return false; - } - else - { - id = id_; - return true; - } - } - }; - - - - - bool ResourceModificationJob::HandleInstance(const std::string& instance) - { - if (modification_.get() == NULL || - output_.get() == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "No modification was provided for this job"); - } - - - LOG(INFO) << "Modifying instance in a job: " << instance; - - - /** - * Retrieve the original instance from the DICOM cache. - **/ - - std::unique_ptr originalHasher; - std::unique_ptr modified; - - try - { - ServerContext::DicomCacheLocker locker(GetContext(), instance); - ParsedDicomFile& original = locker.GetDicom(); - - originalHasher.reset(new DicomInstanceHasher(original.GetHasher())); - modified.reset(original.Clone(true)); - } - catch (OrthancException& e) - { - LOG(WARNING) << "An error occurred while executing a Modification job on instance " << instance << ": " << e.GetDetails(); - return false; - } - - - /** - * Compute the resulting DICOM instance. - **/ - - modification_->Apply(*modified); - - const std::string modifiedUid = IDicomTranscoder::GetSopInstanceUid(modified->GetDcmtkObject()); - - if (transcode_) - { - std::set syntaxes; - syntaxes.insert(transferSyntax_); - - IDicomTranscoder::DicomImage source; - source.AcquireParsed(*modified); // "modified" is invalid below this point - - IDicomTranscoder::DicomImage transcoded; - if (GetContext().Transcode(transcoded, source, syntaxes, true)) - { - modified.reset(transcoded.ReleaseAsParsedDicomFile()); - - // Fix the SOP instance UID in order the preserve the - // references between instance UIDs in the DICOM hierarchy - // (the UID might have changed in the case of lossy transcoding) - if (modified.get() == NULL || - modified->GetDcmtkObject().getDataset() == NULL || - !modified->GetDcmtkObject().getDataset()->putAndInsertString( - DCM_SOPInstanceUID, modifiedUid.c_str(), OFTrue /* replace */).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - else - { - LOG(WARNING) << "Cannot transcode instance, keeping original transfer syntax: " << instance; - modified.reset(source.ReleaseAsParsedDicomFile()); - } - } - - assert(modifiedUid == IDicomTranscoder::GetSopInstanceUid(modified->GetDcmtkObject())); - - DicomInstanceToStore toStore; - toStore.SetOrigin(origin_); - toStore.SetParsedDicomFile(*modified); - - - /** - * Prepare the metadata information to associate with the - * resulting DICOM instance (AnonymizedFrom/ModifiedFrom). - **/ - - DicomInstanceHasher modifiedHasher = modified->GetHasher(); - - MetadataType metadataType = (isAnonymization_ ? - MetadataType_AnonymizedFrom : - MetadataType_ModifiedFrom); - - if (originalHasher->HashSeries() != modifiedHasher.HashSeries()) - { - toStore.AddMetadata(ResourceType_Series, metadataType, originalHasher->HashSeries()); - } - - if (originalHasher->HashStudy() != modifiedHasher.HashStudy()) - { - toStore.AddMetadata(ResourceType_Study, metadataType, originalHasher->HashStudy()); - } - - if (originalHasher->HashPatient() != modifiedHasher.HashPatient()) - { - toStore.AddMetadata(ResourceType_Patient, metadataType, originalHasher->HashPatient()); - } - - assert(instance == originalHasher->HashInstance()); - toStore.AddMetadata(ResourceType_Instance, metadataType, instance); - - - /** - * Store the resulting DICOM instance into the Orthanc store. - **/ - - std::string modifiedInstance; - if (GetContext().Store(modifiedInstance, toStore, - StoreInstanceMode_Default) != StoreStatus_Success) - { - throw OrthancException(ErrorCode_CannotStoreInstance, - "Error while storing a modified instance " + instance); - } - - /** - * The assertion below will fail if automated transcoding to a - * lossy transfer syntax is enabled in the Orthanc core, and if - * the source instance is not in this transfer syntax. - **/ - // assert(modifiedInstance == modifiedHasher.HashInstance()); - - output_->Update(modifiedHasher); - - return true; - } - - - ResourceModificationJob::ResourceModificationJob(ServerContext& context) : - CleaningInstancesJob(context, true /* by default, keep source */), - modification_(new DicomModification), - isAnonymization_(false), - transcode_(false) - { - } - - - void ResourceModificationJob::SetModification(DicomModification* modification, - ResourceType level, - bool isAnonymization) - { - if (modification == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - modification_.reset(modification); - output_.reset(new Output(level)); - isAnonymization_ = isAnonymization; - } - } - - - void ResourceModificationJob::SetOrigin(const DicomInstanceOrigin& origin) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - origin_ = origin; - } - } - - - void ResourceModificationJob::SetOrigin(const RestApiCall& call) - { - SetOrigin(DicomInstanceOrigin::FromRest(call)); - } - - - const DicomModification& ResourceModificationJob::GetModification() const - { - if (modification_.get() == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return *modification_; - } - } - - - DicomTransferSyntax ResourceModificationJob::GetTransferSyntax() const - { - if (transcode_) - { - return transferSyntax_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - - void ResourceModificationJob::SetTranscode(DicomTransferSyntax syntax) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - transcode_ = true; - transferSyntax_ = syntax; - } - } - - - void ResourceModificationJob::SetTranscode(const std::string& transferSyntaxUid) - { - DicomTransferSyntax s; - if (LookupTransferSyntax(s, transferSyntaxUid)) - { - SetTranscode(s); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, - "Unknown transfer syntax UID: " + transferSyntaxUid); - } - } - - - void ResourceModificationJob::ClearTranscode() - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - transcode_ = false; - } - } - - - void ResourceModificationJob::GetPublicContent(Json::Value& value) - { - CleaningInstancesJob::GetPublicContent(value); - - value["IsAnonymization"] = isAnonymization_; - - if (output_.get() != NULL) - { - output_->Format(value); - } - - if (transcode_) - { - value["Transcode"] = GetTransferSyntaxUid(transferSyntax_); - } - } - - - static const char* MODIFICATION = "Modification"; - static const char* ORIGIN = "Origin"; - static const char* IS_ANONYMIZATION = "IsAnonymization"; - static const char* TRANSCODE = "Transcode"; - - - ResourceModificationJob::ResourceModificationJob(ServerContext& context, - const Json::Value& serialized) : - CleaningInstancesJob(context, serialized, true /* by default, keep source */) - { - assert(serialized.type() == Json::objectValue); - - isAnonymization_ = SerializationToolbox::ReadBoolean(serialized, IS_ANONYMIZATION); - origin_ = DicomInstanceOrigin(serialized[ORIGIN]); - modification_.reset(new DicomModification(serialized[MODIFICATION])); - - if (serialized.isMember(TRANSCODE)) - { - SetTranscode(SerializationToolbox::ReadString(serialized, TRANSCODE)); - } - else - { - transcode_ = false; - } - } - - bool ResourceModificationJob::Serialize(Json::Value& value) - { - if (!CleaningInstancesJob::Serialize(value)) - { - return false; - } - else - { - assert(value.type() == Json::objectValue); - - value[IS_ANONYMIZATION] = isAnonymization_; - - if (transcode_) - { - value[TRANSCODE] = GetTransferSyntaxUid(transferSyntax_); - } - - origin_.Serialize(value[ORIGIN]); - - Json::Value tmp; - modification_->Serialize(tmp); - value[MODIFICATION] = tmp; - - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/ResourceModificationJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomParsing/DicomModification.h" -#include "../DicomInstanceOrigin.h" -#include "CleaningInstancesJob.h" - -namespace Orthanc -{ - class ServerContext; - - class ResourceModificationJob : public CleaningInstancesJob - { - private: - class Output; - - std::unique_ptr modification_; - boost::shared_ptr output_; - bool isAnonymization_; - DicomInstanceOrigin origin_; - bool transcode_; - DicomTransferSyntax transferSyntax_; - - protected: - virtual bool HandleInstance(const std::string& instance); - - public: - ResourceModificationJob(ServerContext& context); - - ResourceModificationJob(ServerContext& context, - const Json::Value& serialized); - - void SetModification(DicomModification* modification, // Takes ownership - ResourceType level, - bool isAnonymization); - - void SetOrigin(const DicomInstanceOrigin& origin); - - void SetOrigin(const RestApiCall& call); - - const DicomModification& GetModification() const; - - bool IsAnonymization() const - { - return isAnonymization_; - } - - const DicomInstanceOrigin& GetOrigin() const - { - return origin_; - } - - bool IsTranscode() const - { - return transcode_; - } - - DicomTransferSyntax GetTransferSyntax() const; - - void SetTranscode(DicomTransferSyntax syntax); - - void SetTranscode(const std::string& transferSyntaxUid); - - void ClearTranscode(); - - virtual void Stop(JobStopReason reason) - { - } - - virtual void GetJobType(std::string& target) - { - target = "ResourceModification"; - } - - virtual void GetPublicContent(Json::Value& value); - - virtual bool Serialize(Json::Value& value); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "SplitStudyJob.h" - -#include "../../Core/DicomParsing/FromDcmtkBridge.h" -#include "../../Core/Logging.h" -#include "../../Core/SerializationToolbox.h" -#include "../ServerContext.h" - - -namespace Orthanc -{ - void SplitStudyJob::CheckAllowedTag(const DicomTag& tag) const - { - if (allowedTags_.find(tag) == allowedTags_.end()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange, - "Cannot modify the following tag while splitting a study " - "(not in the patient/study modules): " + - FromDcmtkBridge::GetTagName(tag, "") + - " (" + tag.Format() + ")"); - } - } - - - void SplitStudyJob::Setup() - { - SetPermissive(false); - - DicomTag::AddTagsForModule(allowedTags_, DicomModule_Patient); - DicomTag::AddTagsForModule(allowedTags_, DicomModule_Study); - allowedTags_.erase(DICOM_TAG_STUDY_INSTANCE_UID); - allowedTags_.erase(DICOM_TAG_SERIES_INSTANCE_UID); - } - - - bool SplitStudyJob::HandleInstance(const std::string& instance) - { - if (!HasTrailingStep()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, - "AddTrailingStep() should have been called after AddSourceSeries()"); - } - - /** - * Retrieve the DICOM instance to be modified - **/ - - std::unique_ptr modified; - - try - { - ServerContext::DicomCacheLocker locker(GetContext(), instance); - modified.reset(locker.GetDicom().Clone(true)); - } - catch (OrthancException&) - { - LOG(WARNING) << "An instance was removed after the job was issued: " << instance; - return false; - } - - - /** - * Chose the target UIDs - **/ - - assert(modified->GetHasher().HashStudy() == sourceStudy_); - - std::string series = modified->GetHasher().HashSeries(); - - SeriesUidMap::const_iterator targetSeriesUid = seriesUidMap_.find(series); - - if (targetSeriesUid == seriesUidMap_.end()) - { - throw OrthancException(ErrorCode_BadFileFormat); // Should never happen - } - - - /** - * Apply user-specified modifications - **/ - - for (std::set::const_iterator it = removals_.begin(); - it != removals_.end(); ++it) - { - modified->Remove(*it); - } - - for (Replacements::const_iterator it = replacements_.begin(); - it != replacements_.end(); ++it) - { - modified->ReplacePlainString(it->first, it->second); - } - - - /** - * Store the new instance into Orthanc - **/ - - modified->ReplacePlainString(DICOM_TAG_STUDY_INSTANCE_UID, targetStudyUid_); - modified->ReplacePlainString(DICOM_TAG_SERIES_INSTANCE_UID, targetSeriesUid->second); - - // Fix since Orthanc 1.5.8: Assign new "SOPInstanceUID", as the instance has been modified - modified->ReplacePlainString(DICOM_TAG_SOP_INSTANCE_UID, FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Instance)); - - if (targetStudy_.empty()) - { - targetStudy_ = modified->GetHasher().HashStudy(); - } - - DicomInstanceToStore toStore; - toStore.SetOrigin(origin_); - toStore.SetParsedDicomFile(*modified); - - std::string modifiedInstance; - if (GetContext().Store(modifiedInstance, toStore, - StoreInstanceMode_Default) != StoreStatus_Success) - { - LOG(ERROR) << "Error while storing a modified instance " << instance; - return false; - } - - return true; - } - - - SplitStudyJob::SplitStudyJob(ServerContext& context, - const std::string& sourceStudy) : - CleaningInstancesJob(context, false /* by default, remove source instances */), - sourceStudy_(sourceStudy), - targetStudyUid_(FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Study)) - { - Setup(); - - ResourceType type; - - if (!GetContext().GetIndex().LookupResourceType(type, sourceStudy) || - type != ResourceType_Study) - { - throw OrthancException(ErrorCode_UnknownResource, - "Cannot split unknown study " + sourceStudy); - } - } - - - void SplitStudyJob::SetOrigin(const DicomInstanceOrigin& origin) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - origin_ = origin; - } - } - - - void SplitStudyJob::SetOrigin(const RestApiCall& call) - { - SetOrigin(DicomInstanceOrigin::FromRest(call)); - } - - - void SplitStudyJob::AddSourceSeries(const std::string& series) - { - std::string parent; - - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else if (!GetContext().GetIndex().LookupParent(parent, series, ResourceType_Study) || - parent != sourceStudy_) - { - throw OrthancException(ErrorCode_UnknownResource, - "This series does not belong to the study to be split: " + series); - } - else - { - // Generate a target SeriesInstanceUID for this series - seriesUidMap_[series] = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Series); - - // Add all the instances of the series as to be processed - std::list instances; - GetContext().GetIndex().GetChildren(instances, series); - - for (std::list::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - AddInstance(*it); - } - } - } - - - bool SplitStudyJob::LookupTargetSeriesUid(std::string& uid, - const std::string& series) const - { - SeriesUidMap::const_iterator found = seriesUidMap_.find(series); - - if (found == seriesUidMap_.end()) - { - return false; - } - else - { - uid = found->second; - return true; - } - } - - - void SplitStudyJob::Remove(const DicomTag& tag) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - CheckAllowedTag(tag); - removals_.insert(tag); - } - - - void SplitStudyJob::Replace(const DicomTag& tag, - const std::string& value) - { - if (IsStarted()) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - CheckAllowedTag(tag); - replacements_[tag] = value; - } - - - bool SplitStudyJob::LookupReplacement(std::string& value, - const DicomTag& tag) const - { - Replacements::const_iterator found = replacements_.find(tag); - - if (found == replacements_.end()) - { - return false; - } - else - { - value = found->second; - return true; - } - } - - - void SplitStudyJob::GetPublicContent(Json::Value& value) - { - CleaningInstancesJob::GetPublicContent(value); - - if (!targetStudy_.empty()) - { - value["TargetStudy"] = targetStudy_; - } - - value["TargetStudyUID"] = targetStudyUid_; - } - - - static const char* SOURCE_STUDY = "SourceStudy"; - static const char* TARGET_STUDY = "TargetStudy"; - static const char* TARGET_STUDY_UID = "TargetStudyUID"; - static const char* SERIES_UID_MAP = "SeriesUIDMap"; - static const char* ORIGIN = "Origin"; - static const char* REPLACEMENTS = "Replacements"; - static const char* REMOVALS = "Removals"; - - - SplitStudyJob::SplitStudyJob(ServerContext& context, - const Json::Value& serialized) : - CleaningInstancesJob(context, serialized, - false /* by default, remove source instances */) // (*) - { - if (!HasTrailingStep()) - { - // Should have been set by (*) - throw OrthancException(ErrorCode_InternalError); - } - - Setup(); - - sourceStudy_ = SerializationToolbox::ReadString(serialized, SOURCE_STUDY); - targetStudy_ = SerializationToolbox::ReadString(serialized, TARGET_STUDY); - targetStudyUid_ = SerializationToolbox::ReadString(serialized, TARGET_STUDY_UID); - SerializationToolbox::ReadMapOfStrings(seriesUidMap_, serialized, SERIES_UID_MAP); - origin_ = DicomInstanceOrigin(serialized[ORIGIN]); - SerializationToolbox::ReadMapOfTags(replacements_, serialized, REPLACEMENTS); - SerializationToolbox::ReadSetOfTags(removals_, serialized, REMOVALS); - } - - - bool SplitStudyJob::Serialize(Json::Value& target) - { - if (!CleaningInstancesJob::Serialize(target)) - { - return false; - } - else - { - target[SOURCE_STUDY] = sourceStudy_; - target[TARGET_STUDY] = targetStudy_; - target[TARGET_STUDY_UID] = targetStudyUid_; - SerializationToolbox::WriteMapOfStrings(target, seriesUidMap_, SERIES_UID_MAP); - origin_.Serialize(target[ORIGIN]); - SerializationToolbox::WriteMapOfTags(target, replacements_, REPLACEMENTS); - SerializationToolbox::WriteSetOfTags(target, removals_, REMOVALS); - - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/SplitStudyJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/DicomFormat/DicomTag.h" -#include "../DicomInstanceOrigin.h" -#include "CleaningInstancesJob.h" - -namespace Orthanc -{ - class ServerContext; - - class SplitStudyJob : public CleaningInstancesJob - { - private: - typedef std::map SeriesUidMap; - typedef std::map Replacements; - - - std::set allowedTags_; - std::string sourceStudy_; - std::string targetStudy_; - std::string targetStudyUid_; - SeriesUidMap seriesUidMap_; - DicomInstanceOrigin origin_; - Replacements replacements_; - std::set removals_; - - void CheckAllowedTag(const DicomTag& tag) const; - - void Setup(); - - protected: - virtual bool HandleInstance(const std::string& instance); - - public: - SplitStudyJob(ServerContext& context, - const std::string& sourceStudy); - - SplitStudyJob(ServerContext& context, - const Json::Value& serialized); - - const std::string& GetSourceStudy() const - { - return sourceStudy_; - } - - const std::string& GetTargetStudy() const - { - return targetStudy_; - } - - const std::string& GetTargetStudyUid() const - { - return targetStudyUid_; - } - - void AddSourceSeries(const std::string& series); - - bool LookupTargetSeriesUid(std::string& uid, - const std::string& series) const; - - void Replace(const DicomTag& tag, - const std::string& value); - - bool LookupReplacement(std::string& value, - const DicomTag& tag) const; - - void Remove(const DicomTag& tag); - - bool IsRemoved(const DicomTag& tag) const - { - return removals_.find(tag) != removals_.end(); - } - - void SetOrigin(const DicomInstanceOrigin& origin); - - void SetOrigin(const RestApiCall& call); - - const DicomInstanceOrigin& GetOrigin() const - { - return origin_; - } - - virtual void Stop(JobStopReason reason) - { - } - - virtual void GetJobType(std::string& target) - { - target = "SplitStudy"; - } - - virtual void GetPublicContent(Json::Value& value); - - virtual bool Serialize(Json::Value& target); - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,455 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "../PrecompiledHeadersServer.h" -#include "StorageCommitmentScpJob.h" - -#include "../../Core/DicomNetworking/DicomAssociation.h" -#include "../../Core/Logging.h" -#include "../../Core/OrthancException.h" -#include "../../Core/SerializationToolbox.h" -#include "../OrthancConfiguration.h" -#include "../ServerContext.h" - - -static const char* ANSWER = "Answer"; -static const char* CALLED_AET = "CalledAet"; -static const char* INDEX = "Index"; -static const char* LOOKUP = "Lookup"; -static const char* REMOTE_MODALITY = "RemoteModality"; -static const char* SETUP = "Setup"; -static const char* SOP_CLASS_UIDS = "SopClassUids"; -static const char* SOP_INSTANCE_UIDS = "SopInstanceUids"; -static const char* TRANSACTION_UID = "TransactionUid"; -static const char* TYPE = "Type"; - - - -namespace Orthanc -{ - class StorageCommitmentScpJob::StorageCommitmentCommand : public SetOfCommandsJob::ICommand - { - public: - virtual CommandType GetType() const = 0; - }; - - - class StorageCommitmentScpJob::SetupCommand : public StorageCommitmentCommand - { - private: - StorageCommitmentScpJob& that_; - - public: - SetupCommand(StorageCommitmentScpJob& that) : - that_(that) - { - } - - virtual CommandType GetType() const ORTHANC_OVERRIDE - { - return CommandType_Setup; - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - that_.Setup(jobId); - return true; - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - target = Json::objectValue; - target[TYPE] = SETUP; - } - }; - - - class StorageCommitmentScpJob::LookupCommand : public StorageCommitmentCommand - { - private: - StorageCommitmentScpJob& that_; - size_t index_; - bool hasFailureReason_; - StorageCommitmentFailureReason failureReason_; - - public: - LookupCommand(StorageCommitmentScpJob& that, - size_t index) : - that_(that), - index_(index), - hasFailureReason_(false) - { - } - - virtual CommandType GetType() const ORTHANC_OVERRIDE - { - return CommandType_Lookup; - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - failureReason_ = that_.Lookup(index_); - hasFailureReason_ = true; - return true; - } - - size_t GetIndex() const - { - return index_; - } - - StorageCommitmentFailureReason GetFailureReason() const - { - if (hasFailureReason_) - { - return failureReason_; - } - else - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - target = Json::objectValue; - target[TYPE] = LOOKUP; - target[INDEX] = static_cast(index_); - } - }; - - - class StorageCommitmentScpJob::AnswerCommand : public StorageCommitmentCommand - { - private: - StorageCommitmentScpJob& that_; - - public: - AnswerCommand(StorageCommitmentScpJob& that) : - that_(that) - { - if (that_.ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - that_.ready_ = true; - } - } - - virtual CommandType GetType() const ORTHANC_OVERRIDE - { - return CommandType_Answer; - } - - virtual bool Execute(const std::string& jobId) ORTHANC_OVERRIDE - { - that_.Answer(); - return true; - } - - virtual void Serialize(Json::Value& target) const ORTHANC_OVERRIDE - { - target = Json::objectValue; - target[TYPE] = ANSWER; - } - }; - - - class StorageCommitmentScpJob::Unserializer : public SetOfCommandsJob::ICommandUnserializer - { - private: - StorageCommitmentScpJob& that_; - - public: - Unserializer(StorageCommitmentScpJob& that) : - that_(that) - { - that_.ready_ = false; - } - - virtual ICommand* Unserialize(const Json::Value& source) const - { - const std::string type = SerializationToolbox::ReadString(source, TYPE); - - if (type == SETUP) - { - return new SetupCommand(that_); - } - else if (type == LOOKUP) - { - return new LookupCommand(that_, SerializationToolbox::ReadUnsignedInteger(source, INDEX)); - } - else if (type == ANSWER) - { - return new AnswerCommand(that_); - } - else - { - throw OrthancException(ErrorCode_BadFileFormat); - } - } - }; - - - void StorageCommitmentScpJob::CheckInvariants() - { - const size_t n = GetCommandsCount(); - - if (n <= 1) - { - throw OrthancException(ErrorCode_InternalError); - } - - for (size_t i = 0; i < n; i++) - { - const CommandType type = dynamic_cast(GetCommand(i)).GetType(); - - if ((i == 0 && type != CommandType_Setup) || - (i >= 1 && i < n - 1 && type != CommandType_Lookup) || - (i == n - 1 && type != CommandType_Answer)) - { - throw OrthancException(ErrorCode_InternalError); - } - - if (type == CommandType_Lookup) - { - const LookupCommand& lookup = dynamic_cast(GetCommand(i)); - if (lookup.GetIndex() != i - 1) - { - throw OrthancException(ErrorCode_InternalError); - } - } - } - } - - - void StorageCommitmentScpJob::Setup(const std::string& jobId) - { - CheckInvariants(); - - const std::string& remoteAet = remoteModality_.GetApplicationEntityTitle(); - lookupHandler_.reset(context_.CreateStorageCommitment(jobId, transactionUid_, sopClassUids_, - sopInstanceUids_, remoteAet, calledAet_)); - } - - - StorageCommitmentFailureReason StorageCommitmentScpJob::Lookup(size_t index) - { -#ifndef NDEBUG - CheckInvariants(); -#endif - - if (index >= sopClassUids_.size()) - { - throw OrthancException(ErrorCode_InternalError); - } - else if (lookupHandler_.get() != NULL) - { - return lookupHandler_->Lookup(sopClassUids_[index], sopInstanceUids_[index]); - } - else - { - // This is the default implementation of Orthanc (if no storage - // commitment plugin is installed) - bool success = false; - StorageCommitmentFailureReason reason = - StorageCommitmentFailureReason_NoSuchObjectInstance /* 0x0112 == 274 */; - - try - { - std::vector orthancId; - context_.GetIndex().LookupIdentifierExact(orthancId, ResourceType_Instance, DICOM_TAG_SOP_INSTANCE_UID, sopInstanceUids_[index]); - - if (orthancId.size() == 1) - { - std::string a, b; - - // Make sure that the DICOM file can be re-read by DCMTK - // from the file storage, and that the actual SOP - // class/instance UIDs do match - ServerContext::DicomCacheLocker locker(context_, orthancId[0]); - if (locker.GetDicom().GetTagValue(a, DICOM_TAG_SOP_CLASS_UID) && - locker.GetDicom().GetTagValue(b, DICOM_TAG_SOP_INSTANCE_UID) && - b == sopInstanceUids_[index]) - { - if (a == sopClassUids_[index]) - { - success = true; - reason = StorageCommitmentFailureReason_Success; - } - else - { - // Mismatch in the SOP class UID - reason = StorageCommitmentFailureReason_ClassInstanceConflict /* 0x0119 */; - } - } - } - } - catch (OrthancException&) - { - } - - LOG(INFO) << " Storage commitment SCP job: " << (success ? "Success" : "Failure") - << " while looking for " << sopClassUids_[index] << " / " << sopInstanceUids_[index]; - - return reason; - } - } - - - void StorageCommitmentScpJob::Answer() - { - CheckInvariants(); - LOG(INFO) << " Storage commitment SCP job: Sending answer"; - - std::vector failureReasons; - failureReasons.reserve(sopClassUids_.size()); - - for (size_t i = 1; i < GetCommandsCount() - 1; i++) - { - const LookupCommand& lookup = dynamic_cast(GetCommand(i)); - failureReasons.push_back(lookup.GetFailureReason()); - } - - if (failureReasons.size() != sopClassUids_.size()) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomAssociationParameters parameters(calledAet_, remoteModality_); - DicomAssociation::ReportStorageCommitment( - parameters, transactionUid_, sopClassUids_, sopInstanceUids_, failureReasons); - } - - - StorageCommitmentScpJob::StorageCommitmentScpJob(ServerContext& context, - const std::string& transactionUid, - const std::string& remoteAet, - const std::string& calledAet) : - context_(context), - ready_(false), - transactionUid_(transactionUid), - calledAet_(calledAet) - { - { - OrthancConfiguration::ReaderLock lock; - if (!lock.GetConfiguration().LookupDicomModalityUsingAETitle(remoteModality_, remoteAet)) - { - throw OrthancException(ErrorCode_InexistentItem, - "Unknown remote modality for storage commitment SCP: " + remoteAet); - } - } - - AddCommand(new SetupCommand(*this)); - } - - - void StorageCommitmentScpJob::Reserve(size_t size) - { - if (ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - sopClassUids_.reserve(size); - sopInstanceUids_.reserve(size); - } - } - - - void StorageCommitmentScpJob::AddInstance(const std::string& sopClassUid, - const std::string& sopInstanceUid) - { - if (ready_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - assert(sopClassUids_.size() == sopInstanceUids_.size()); - AddCommand(new LookupCommand(*this, sopClassUids_.size())); - sopClassUids_.push_back(sopClassUid); - sopInstanceUids_.push_back(sopInstanceUid); - } - } - - - void StorageCommitmentScpJob::MarkAsReady() - { - AddCommand(new AnswerCommand(*this)); - } - - - void StorageCommitmentScpJob::GetPublicContent(Json::Value& value) - { - SetOfCommandsJob::GetPublicContent(value); - - value["CalledAet"] = calledAet_; - value["RemoteAet"] = remoteModality_.GetApplicationEntityTitle(); - value["TransactionUid"] = transactionUid_; - } - - - StorageCommitmentScpJob::StorageCommitmentScpJob(ServerContext& context, - const Json::Value& serialized) : - SetOfCommandsJob(new Unserializer(*this), serialized), - context_(context) - { - transactionUid_ = SerializationToolbox::ReadString(serialized, TRANSACTION_UID); - remoteModality_ = RemoteModalityParameters(serialized[REMOTE_MODALITY]); - calledAet_ = SerializationToolbox::ReadString(serialized, CALLED_AET); - SerializationToolbox::ReadArrayOfStrings(sopClassUids_, serialized, SOP_CLASS_UIDS); - SerializationToolbox::ReadArrayOfStrings(sopInstanceUids_, serialized, SOP_INSTANCE_UIDS); - } - - - bool StorageCommitmentScpJob::Serialize(Json::Value& target) - { - if (!SetOfCommandsJob::Serialize(target)) - { - return false; - } - else - { - target[TRANSACTION_UID] = transactionUid_; - remoteModality_.Serialize(target[REMOTE_MODALITY], true /* force advanced format */); - target[CALLED_AET] = calledAet_; - SerializationToolbox::WriteArrayOfStrings(target, sopClassUids_, SOP_CLASS_UIDS); - SerializationToolbox::WriteArrayOfStrings(target, sopInstanceUids_, SOP_INSTANCE_UIDS); - return true; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerJobs/StorageCommitmentScpJob.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../../Core/Compatibility.h" -#include "../../Core/DicomNetworking/RemoteModalityParameters.h" -#include "../../Core/JobsEngine/SetOfCommandsJob.h" -#include "IStorageCommitmentFactory.h" - -#include -#include - -namespace Orthanc -{ - class ServerContext; - - class StorageCommitmentScpJob : public SetOfCommandsJob - { - private: - enum CommandType - { - CommandType_Setup, - CommandType_Lookup, - CommandType_Answer - }; - - class StorageCommitmentCommand; - class SetupCommand; - class LookupCommand; - class AnswerCommand; - class Unserializer; - - ServerContext& context_; - bool ready_; - std::string transactionUid_; - RemoteModalityParameters remoteModality_; - std::string calledAet_; - std::vector sopClassUids_; - std::vector sopInstanceUids_; - - std::unique_ptr lookupHandler_; - - void CheckInvariants(); - - void Setup(const std::string& jobId); - - StorageCommitmentFailureReason Lookup(size_t index); - - void Answer(); - - public: - StorageCommitmentScpJob(ServerContext& context, - const std::string& transactionUid, - const std::string& remoteAet, - const std::string& calledAet); - - StorageCommitmentScpJob(ServerContext& context, - const Json::Value& serialized); - - void Reserve(size_t size); - - void AddInstance(const std::string& sopClassUid, - const std::string& sopInstanceUid); - - void MarkAsReady(); - - virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE - { - } - - virtual void GetJobType(std::string& target) ORTHANC_OVERRIDE - { - target = "StorageCommitmentScp"; - } - - virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE; - - virtual bool Serialize(Json::Value& target) ORTHANC_OVERRIDE; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,455 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "ServerToolbox.h" - -#include "../Core/DicomFormat/DicomArray.h" -#include "../Core/DicomParsing/ParsedDicomFile.h" -#include "../Core/FileStorage/StorageAccessor.h" -#include "../Core/Logging.h" -#include "../Core/OrthancException.h" -#include "Database/IDatabaseWrapper.h" -#include "Database/ResourcesContent.h" -#include "ServerContext.h" - -#include - -namespace Orthanc -{ - static const DicomTag PATIENT_IDENTIFIERS[] = - { - DICOM_TAG_PATIENT_ID, - DICOM_TAG_PATIENT_NAME, - DICOM_TAG_PATIENT_BIRTH_DATE - }; - - static const DicomTag STUDY_IDENTIFIERS[] = - { - DICOM_TAG_PATIENT_ID, - DICOM_TAG_PATIENT_NAME, - DICOM_TAG_PATIENT_BIRTH_DATE, - DICOM_TAG_STUDY_INSTANCE_UID, - DICOM_TAG_ACCESSION_NUMBER, - DICOM_TAG_STUDY_DESCRIPTION, - DICOM_TAG_STUDY_DATE - }; - - static const DicomTag SERIES_IDENTIFIERS[] = - { - DICOM_TAG_SERIES_INSTANCE_UID - }; - - static const DicomTag INSTANCE_IDENTIFIERS[] = - { - DICOM_TAG_SOP_INSTANCE_UID - }; - - - static void StoreMainDicomTagsInternal(ResourcesContent& target, - int64_t resource, - const DicomMap& tags) - { - DicomArray flattened(tags); - - for (size_t i = 0; i < flattened.GetSize(); i++) - { - const DicomElement& element = flattened.GetElement(i); - const DicomTag& tag = element.GetTag(); - const DicomValue& value = element.GetValue(); - if (!value.IsNull() && - !value.IsBinary()) - { - target.AddMainDicomTag(resource, tag, element.GetValue().GetContent()); - } - } - } - - - static void StoreIdentifiers(ResourcesContent& target, - int64_t resource, - ResourceType level, - const DicomMap& map) - { - const DicomTag* tags; - size_t size; - - ServerToolbox::LoadIdentifiers(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - // The identifiers tags are a subset of the main DICOM tags - assert(DicomMap::IsMainDicomTag(tags[i])); - - const DicomValue* value = map.TestAndGetValue(tags[i]); - if (value != NULL && - !value->IsNull() && - !value->IsBinary()) - { - std::string s = ServerToolbox::NormalizeIdentifier(value->GetContent()); - target.AddIdentifierTag(resource, tags[i], s); - } - } - } - - - void ResourcesContent::AddResource(int64_t resource, - ResourceType level, - const DicomMap& dicomSummary) - { - StoreIdentifiers(*this, resource, level, dicomSummary); - - DicomMap tags; - - switch (level) - { - case ResourceType_Patient: - dicomSummary.ExtractPatientInformation(tags); - break; - - case ResourceType_Study: - // Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6) - dicomSummary.ExtractPatientInformation(tags); - StoreMainDicomTagsInternal(*this, resource, tags); - - dicomSummary.ExtractStudyInformation(tags); - break; - - case ResourceType_Series: - dicomSummary.ExtractSeriesInformation(tags); - break; - - case ResourceType_Instance: - dicomSummary.ExtractInstanceInformation(tags); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - StoreMainDicomTagsInternal(*this, resource, tags); - } - - - namespace ServerToolbox - { - void SimplifyTags(Json::Value& target, - const Json::Value& source, - DicomToJsonFormat format) - { - if (!source.isObject()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - target = Json::objectValue; - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& v = source[members[i]]; - const std::string& type = v["Type"].asString(); - - std::string name; - switch (format) - { - case DicomToJsonFormat_Human: - name = v["Name"].asString(); - break; - - case DicomToJsonFormat_Short: - name = members[i]; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (type == "String") - { - target[name] = v["Value"].asString(); - } - else if (type == "TooLong" || - type == "Null") - { - target[name] = Json::nullValue; - } - else if (type == "Sequence") - { - const Json::Value& array = v["Value"]; - assert(array.isArray()); - - Json::Value children = Json::arrayValue; - for (Json::Value::ArrayIndex i = 0; i < array.size(); i++) - { - Json::Value c; - SimplifyTags(c, array[i], format); - children.append(c); - } - - target[name] = children; - } - else - { - assert(0); - } - } - } - - - bool FindOneChildInstance(int64_t& result, - IDatabaseWrapper& database, - int64_t resource, - ResourceType type) - { - for (;;) - { - if (type == ResourceType_Instance) - { - result = resource; - return true; - } - - std::list children; - database.GetChildrenInternalId(children, resource); - if (children.empty()) - { - return false; - } - - resource = children.front(); - type = GetChildResourceType(type); - } - } - - - void ReconstructMainDicomTags(IDatabaseWrapper& database, - IStorageArea& storageArea, - ResourceType level) - { - // WARNING: The database should be locked with a transaction! - - // TODO: This function might consume much memory if level == - // ResourceType_Instance. To improve this, first download the - // list of studies, then remove the instances for each single - // study (check out OrthancRestApi::InvalidateTags for an - // example). Take this improvement into consideration for the - // next upgrade of the database schema. - - const char* plural = NULL; - - switch (level) - { - case ResourceType_Patient: - plural = "patients"; - break; - - case ResourceType_Study: - plural = "studies"; - break; - - case ResourceType_Series: - plural = "series"; - break; - - case ResourceType_Instance: - plural = "instances"; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - LOG(WARNING) << "Upgrade: Reconstructing the main DICOM tags of all the " << plural << "..."; - - std::list resources; - database.GetAllPublicIds(resources, level); - - for (std::list::const_iterator - it = resources.begin(); it != resources.end(); ++it) - { - // Locate the resource and one of its child instances - int64_t resource, instance; - ResourceType tmp; - - if (!database.LookupResource(resource, tmp, *it) || - tmp != level || - !FindOneChildInstance(instance, database, resource, level)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot find an instance for " + - std::string(EnumerationToString(level)) + - " with identifier " + *it); - } - - // Get the DICOM file attached to some instances in the resource - FileInfo attachment; - if (!database.LookupAttachment(attachment, instance, FileContentType_Dicom)) - { - throw OrthancException(ErrorCode_InternalError, - "Cannot retrieve the DICOM file associated with instance " + - database.GetPublicId(instance)); - } - - try - { - // Read and parse the content of the DICOM file - StorageAccessor accessor(storageArea); - - std::string content; - accessor.Read(content, attachment); - - ParsedDicomFile dicom(content); - - // Update the tags of this resource - DicomMap dicomSummary; - dicom.ExtractDicomSummary(dicomSummary); - - database.ClearMainDicomTags(resource); - - ResourcesContent tags; - tags.AddResource(resource, level, dicomSummary); - database.SetResourcesContent(tags); - } - catch (OrthancException&) - { - LOG(ERROR) << "Cannot decode the DICOM file with UUID " << attachment.GetUuid() - << " associated with instance " << database.GetPublicId(instance); - throw; - } - } - } - - - void LoadIdentifiers(const DicomTag*& tags, - size_t& size, - ResourceType level) - { - switch (level) - { - case ResourceType_Patient: - tags = PATIENT_IDENTIFIERS; - size = sizeof(PATIENT_IDENTIFIERS) / sizeof(DicomTag); - break; - - case ResourceType_Study: - tags = STUDY_IDENTIFIERS; - size = sizeof(STUDY_IDENTIFIERS) / sizeof(DicomTag); - break; - - case ResourceType_Series: - tags = SERIES_IDENTIFIERS; - size = sizeof(SERIES_IDENTIFIERS) / sizeof(DicomTag); - break; - - case ResourceType_Instance: - tags = INSTANCE_IDENTIFIERS; - size = sizeof(INSTANCE_IDENTIFIERS) / sizeof(DicomTag); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - std::string NormalizeIdentifier(const std::string& value) - { - std::string t; - t.reserve(value.size()); - - for (size_t i = 0; i < value.size(); i++) - { - if (value[i] == '%' || - value[i] == '_') - { - t.push_back(' '); // These characters might break wildcard queries in SQL - } - else if (isascii(value[i]) && - !iscntrl(value[i]) && - (!isspace(value[i]) || value[i] == ' ')) - { - t.push_back(value[i]); - } - } - - Toolbox::ToUpperCase(t); - - return Toolbox::StripSpaces(t); - } - - - bool IsIdentifier(const DicomTag& tag, - ResourceType level) - { - const DicomTag* tags; - size_t size; - - LoadIdentifiers(tags, size, level); - - for (size_t i = 0; i < size; i++) - { - if (tag == tags[i]) - { - return true; - } - } - - return false; - } - - - void ReconstructResource(ServerContext& context, - const std::string& resource) - { - LOG(WARNING) << "Reconstructing resource " << resource; - - std::list instances; - context.GetIndex().GetChildInstances(instances, resource); - - for (std::list::const_iterator - it = instances.begin(); it != instances.end(); ++it) - { - ServerContext::DicomCacheLocker locker(context, *it); - - Json::Value dicomAsJson; - locker.GetDicom().DatasetToJson(dicomAsJson); - - std::string s = dicomAsJson.toStyledString(); - context.AddAttachment(*it, FileContentType_DicomAsJson, s.c_str(), s.size()); - - context.GetIndex().ReconstructInstance(locker.GetDicom()); - } - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/ServerToolbox.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "ServerEnumerations.h" - -#include -#include -#include - -namespace Orthanc -{ - class ServerContext; - class IDatabaseWrapper; - class IStorageArea; - - namespace ServerToolbox - { - void SimplifyTags(Json::Value& target, - const Json::Value& source, - DicomToJsonFormat format); - - bool FindOneChildInstance(int64_t& result, - IDatabaseWrapper& database, - int64_t resource, - ResourceType type); - - void ReconstructMainDicomTags(IDatabaseWrapper& database, - IStorageArea& storageArea, - ResourceType level); - - void LoadIdentifiers(const DicomTag*& tags, - size_t& size, - ResourceType level); - - bool IsIdentifier(const DicomTag& tag, - ResourceType level); - - std::string NormalizeIdentifier(const std::string& value); - - void ReconstructResource(ServerContext& context, - const std::string& resource); - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,491 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "SliceOrdering.h" - -#include "../Core/Logging.h" -#include "../Core/Toolbox.h" -#include "ServerEnumerations.h" -#include "ServerIndex.h" - -#include -#include -#include - - -namespace Orthanc -{ - static bool TokenizeVector(std::vector& result, - const std::string& value, - unsigned int expectedSize) - { - std::vector tokens; - Toolbox::TokenizeString(tokens, value, '\\'); - - if (tokens.size() != expectedSize) - { - return false; - } - - result.resize(tokens.size()); - - for (size_t i = 0; i < tokens.size(); i++) - { - try - { - result[i] = boost::lexical_cast(tokens[i]); - } - catch (boost::bad_lexical_cast&) - { - return false; - } - } - - return true; - } - - - static bool TokenizeVector(std::vector& result, - const DicomMap& map, - const DicomTag& tag, - unsigned int expectedSize) - { - const DicomValue* value = map.TestAndGetValue(tag); - - if (value == NULL || - value->IsNull() || - value->IsBinary()) - { - return false; - } - else - { - return TokenizeVector(result, value->GetContent(), expectedSize); - } - } - - - static bool IsCloseToZero(double x) - { - return fabs(x) < 10.0 * std::numeric_limits::epsilon(); - } - - - bool SliceOrdering::ComputeNormal(Vector& normal, - const DicomMap& dicom) - { - std::vector cosines; - - if (TokenizeVector(cosines, dicom, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, 6)) - { - assert(cosines.size() == 6); - normal[0] = cosines[1] * cosines[5] - cosines[2] * cosines[4]; - normal[1] = cosines[2] * cosines[3] - cosines[0] * cosines[5]; - normal[2] = cosines[0] * cosines[4] - cosines[1] * cosines[3]; - return true; - } - else - { - return false; - } - } - - - bool SliceOrdering::IsParallelOrOpposite(const Vector& u, - const Vector& v) - { - // Check out "GeometryToolbox::IsParallelOrOpposite()" in Stone of - // Orthanc for explanations - const double u1 = u[0]; - const double u2 = u[1]; - const double u3 = u[2]; - const double normU = sqrt(u1 * u1 + u2 * u2 + u3 * u3); - - const double v1 = v[0]; - const double v2 = v[1]; - const double v3 = v[2]; - const double normV = sqrt(v1 * v1 + v2 * v2 + v3 * v3); - - if (IsCloseToZero(normU * normV)) - { - return false; - } - else - { - const double cosAngle = (u1 * v1 + u2 * v2 + u3 * v3) / (normU * normV); - - return (IsCloseToZero(cosAngle - 1.0) || // Close to +1: Parallel, non-opposite - IsCloseToZero(fabs(cosAngle) - 1.0)); // Close to -1: Parallel, opposite - } - } - - - struct SliceOrdering::Instance : public boost::noncopyable - { - private: - std::string instanceId_; - bool hasPosition_; - Vector position_; - bool hasNormal_; - Vector normal_; - bool hasIndexInSeries_; - size_t indexInSeries_; - unsigned int framesCount_; - - public: - Instance(ServerIndex& index, - const std::string& instanceId) : - instanceId_(instanceId), - framesCount_(1) - { - DicomMap instance; - if (!index.GetMainDicomTags(instance, instanceId, ResourceType_Instance, ResourceType_Instance)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - const DicomValue* frames = instance.TestAndGetValue(DICOM_TAG_NUMBER_OF_FRAMES); - if (frames != NULL && - !frames->IsNull() && - !frames->IsBinary()) - { - try - { - framesCount_ = boost::lexical_cast(frames->GetContent()); - } - catch (boost::bad_lexical_cast&) - { - } - } - - std::vector tmp; - hasPosition_ = TokenizeVector(tmp, instance, DICOM_TAG_IMAGE_POSITION_PATIENT, 3); - - if (hasPosition_) - { - position_[0] = tmp[0]; - position_[1] = tmp[1]; - position_[2] = tmp[2]; - } - - hasNormal_ = ComputeNormal(normal_, instance); - - std::string s; - hasIndexInSeries_ = false; - - try - { - if (index.LookupMetadata(s, instanceId, MetadataType_Instance_IndexInSeries)) - { - indexInSeries_ = boost::lexical_cast(s); - hasIndexInSeries_ = true; - } - } - catch (boost::bad_lexical_cast&) - { - } - } - - const std::string& GetIdentifier() const - { - return instanceId_; - } - - bool HasPosition() const - { - return hasPosition_; - } - - float ComputeRelativePosition(const Vector& normal) const - { - assert(HasPosition()); - return (normal[0] * position_[0] + - normal[1] * position_[1] + - normal[2] * position_[2]); - } - - bool HasIndexInSeries() const - { - return hasIndexInSeries_; - } - - size_t GetIndexInSeries() const - { - assert(HasIndexInSeries()); - return indexInSeries_; - } - - unsigned int GetFramesCount() const - { - return framesCount_; - } - - bool HasNormal() const - { - return hasNormal_; - } - - const Vector& GetNormal() const - { - assert(hasNormal_); - return normal_; - } - }; - - - class SliceOrdering::PositionComparator - { - private: - const Vector& normal_; - - public: - PositionComparator(const Vector& normal) : normal_(normal) - { - } - - int operator() (const Instance* a, - const Instance* b) const - { - return a->ComputeRelativePosition(normal_) < b->ComputeRelativePosition(normal_); - } - }; - - - bool SliceOrdering::IndexInSeriesComparator(const SliceOrdering::Instance* a, - const SliceOrdering::Instance* b) - { - return a->GetIndexInSeries() < b->GetIndexInSeries(); - } - - - void SliceOrdering::ComputeNormal() - { - DicomMap series; - if (!index_.GetMainDicomTags(series, seriesId_, ResourceType_Series, ResourceType_Series)) - { - throw OrthancException(ErrorCode_UnknownResource); - } - - hasNormal_ = ComputeNormal(normal_, series); - } - - - void SliceOrdering::CreateInstances() - { - std::list instancesId; - index_.GetChildren(instancesId, seriesId_); - - instances_.reserve(instancesId.size()); - for (std::list::const_iterator - it = instancesId.begin(); it != instancesId.end(); ++it) - { - instances_.push_back(new Instance(index_, *it)); - } - } - - - bool SliceOrdering::SortUsingPositions() - { - if (instances_.size() <= 1) - { - // One single instance: It is sorted by default - return true; - } - - if (!hasNormal_) - { - return false; - } - - for (size_t i = 0; i < instances_.size(); i++) - { - assert(instances_[i] != NULL); - - if (!instances_[i]->HasPosition() || - (instances_[i]->HasNormal() && - !IsParallelOrOpposite(instances_[i]->GetNormal(), normal_))) - { - return false; - } - } - - PositionComparator comparator(normal_); - std::sort(instances_.begin(), instances_.end(), comparator); - - float a = instances_[0]->ComputeRelativePosition(normal_); - for (size_t i = 1; i < instances_.size(); i++) - { - float b = instances_[i]->ComputeRelativePosition(normal_); - - if (std::fabs(b - a) <= 10.0f * std::numeric_limits::epsilon()) - { - // Not enough space between two slices along the normal of the volume - return false; - } - - a = b; - } - - // This is a 3D volume - isVolume_ = true; - return true; - } - - - bool SliceOrdering::SortUsingIndexInSeries() - { - if (instances_.size() <= 1) - { - // One single instance: It is sorted by default - return true; - } - - for (size_t i = 0; i < instances_.size(); i++) - { - assert(instances_[i] != NULL); - if (!instances_[i]->HasIndexInSeries()) - { - return false; - } - } - - std::sort(instances_.begin(), instances_.end(), IndexInSeriesComparator); - - for (size_t i = 1; i < instances_.size(); i++) - { - if (instances_[i - 1]->GetIndexInSeries() == instances_[i]->GetIndexInSeries()) - { - // The current "IndexInSeries" occurs 2 times: Not a proper ordering - LOG(WARNING) << "This series contains 2 slices with the same index, trying to display it anyway"; - break; - } - } - - return true; - } - - - SliceOrdering::SliceOrdering(ServerIndex& index, - const std::string& seriesId) : - index_(index), - seriesId_(seriesId), - isVolume_(false) - { - ComputeNormal(); - CreateInstances(); - - if (!SortUsingPositions() && - !SortUsingIndexInSeries()) - { - throw OrthancException(ErrorCode_CannotOrderSlices, - "Unable to order the slices of series " + seriesId); - } - } - - - SliceOrdering::~SliceOrdering() - { - for (std::vector::iterator - it = instances_.begin(); it != instances_.end(); ++it) - { - if (*it != NULL) - { - delete *it; - } - } - } - - - const std::string& SliceOrdering::GetInstanceId(size_t index) const - { - if (index >= instances_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return instances_[index]->GetIdentifier(); - } - } - - - unsigned int SliceOrdering::GetFramesCount(size_t index) const - { - if (index >= instances_.size()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - else - { - return instances_[index]->GetFramesCount(); - } - } - - - void SliceOrdering::Format(Json::Value& result) const - { - result = Json::objectValue; - result["Type"] = (isVolume_ ? "Volume" : "Sequence"); - - Json::Value tmp = Json::arrayValue; - for (size_t i = 0; i < GetInstancesCount(); i++) - { - tmp.append(GetBasePath(ResourceType_Instance, GetInstanceId(i)) + "/file"); - } - - result["Dicom"] = tmp; - - Json::Value slicesShort = Json::arrayValue; - - tmp.clear(); - for (size_t i = 0; i < GetInstancesCount(); i++) - { - std::string base = GetBasePath(ResourceType_Instance, GetInstanceId(i)); - for (size_t j = 0; j < GetFramesCount(i); j++) - { - tmp.append(base + "/frames/" + boost::lexical_cast(j)); - } - - Json::Value tmp2 = Json::arrayValue; - tmp2.append(GetInstanceId(i)); - tmp2.append(0); - tmp2.append(GetFramesCount(i)); - - slicesShort.append(tmp2); - } - - result["Slices"] = tmp; - result["SlicesShort"] = slicesShort; - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/SliceOrdering.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/DicomFormat/DicomMap.h" - -namespace Orthanc -{ - class ServerIndex; - - class SliceOrdering - { - private: - typedef float Vector[3]; - - struct Instance; - class PositionComparator; - - ServerIndex& index_; - std::string seriesId_; - bool hasNormal_; - Vector normal_; - std::vector instances_; - bool isVolume_; - - static bool ComputeNormal(Vector& normal, - const DicomMap& dicom); - - static bool IsParallelOrOpposite(const Vector& a, - const Vector& b); - - static bool IndexInSeriesComparator(const SliceOrdering::Instance* a, - const SliceOrdering::Instance* b); - - void ComputeNormal(); - - void CreateInstances(); - - bool SortUsingPositions(); - - bool SortUsingIndexInSeries(); - - public: - SliceOrdering(ServerIndex& index, - const std::string& seriesId); - - ~SliceOrdering(); - - size_t GetInstancesCount() const - { - return instances_.size(); - } - - const std::string& GetInstanceId(size_t index) const; - - unsigned int GetFramesCount(size_t index) const; - - void Format(Json::Value& result) const; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,272 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "PrecompiledHeadersServer.h" -#include "StorageCommitmentReports.h" - -#include "../Core/OrthancException.h" - -namespace Orthanc -{ - void StorageCommitmentReports::Report::MarkAsComplete() - { - if (isComplete_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - isComplete_ = true; - } - } - - void StorageCommitmentReports::Report::AddSuccess(const std::string& sopClassUid, - const std::string& sopInstanceUid) - { - if (isComplete_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - Success success; - success.sopClassUid_ = sopClassUid; - success.sopInstanceUid_ = sopInstanceUid; - success_.push_back(success); - } - } - - void StorageCommitmentReports::Report::AddFailure(const std::string& sopClassUid, - const std::string& sopInstanceUid, - StorageCommitmentFailureReason reason) - { - if (isComplete_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - Failure failure; - failure.sopClassUid_ = sopClassUid; - failure.sopInstanceUid_ = sopInstanceUid; - failure.reason_ = reason; - failures_.push_back(failure); - } - } - - - StorageCommitmentReports::Report::Status StorageCommitmentReports::Report::GetStatus() const - { - if (!isComplete_) - { - return Status_Pending; - } - else if (failures_.empty()) - { - return Status_Success; - } - else - { - return Status_Failure; - } - } - - - void StorageCommitmentReports::Report::Format(Json::Value& json) const - { - static const char* const FIELD_STATUS = "Status"; - static const char* const FIELD_SOP_CLASS_UID = "SOPClassUID"; - static const char* const FIELD_SOP_INSTANCE_UID = "SOPInstanceUID"; - static const char* const FIELD_FAILURE_REASON = "FailureReason"; - static const char* const FIELD_DESCRIPTION = "Description"; - static const char* const FIELD_REMOTE_AET = "RemoteAET"; - static const char* const FIELD_SUCCESS = "Success"; - static const char* const FIELD_FAILURES = "Failures"; - - - json = Json::objectValue; - json[FIELD_REMOTE_AET] = remoteAet_; - - bool pending; - - switch (GetStatus()) - { - case Status_Pending: - json[FIELD_STATUS] = "Pending"; - pending = true; - break; - - case Status_Success: - json[FIELD_STATUS] = "Success"; - pending = false; - break; - - case Status_Failure: - json[FIELD_STATUS] = "Failure"; - pending = false; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - if (!pending) - { - { - Json::Value success = Json::arrayValue; - for (std::list::const_iterator - it = success_.begin(); it != success_.end(); ++it) - { - Json::Value item = Json::objectValue; - item[FIELD_SOP_CLASS_UID] = it->sopClassUid_; - item[FIELD_SOP_INSTANCE_UID] = it->sopInstanceUid_; - success.append(item); - } - - json[FIELD_SUCCESS] = success; - } - - { - Json::Value failures = Json::arrayValue; - for (std::list::const_iterator - it = failures_.begin(); it != failures_.end(); ++it) - { - Json::Value item = Json::objectValue; - item[FIELD_SOP_CLASS_UID] = it->sopClassUid_; - item[FIELD_SOP_INSTANCE_UID] = it->sopInstanceUid_; - item[FIELD_FAILURE_REASON] = it->reason_; - item[FIELD_DESCRIPTION] = EnumerationToString(it->reason_); - failures.append(item); - } - - json[FIELD_FAILURES] = failures; - } - } - } - - - void StorageCommitmentReports::Report::GetSuccessSopInstanceUids( - std::vector& target) const - { - target.clear(); - target.reserve(success_.size()); - - for (std::list::const_iterator - it = success_.begin(); it != success_.end(); ++it) - { - target.push_back(it->sopInstanceUid_); - } - } - - - StorageCommitmentReports::~StorageCommitmentReports() - { - while (!content_.IsEmpty()) - { - Report* report = NULL; - content_.RemoveOldest(report); - - assert(report != NULL); - delete report; - } - } - - - void StorageCommitmentReports::Store(const std::string& transactionUid, - Report* report) - { - std::unique_ptr protection(report); - - boost::mutex::scoped_lock lock(mutex_); - - { - Report* previous = NULL; - if (content_.Contains(transactionUid, previous)) - { - assert(previous != NULL); - delete previous; - - content_.Invalidate(transactionUid); - } - } - - assert(maxSize_ == 0 || - content_.GetSize() <= maxSize_); - - if (maxSize_ != 0 && - content_.GetSize() == maxSize_) - { - assert(!content_.IsEmpty()); - - Report* oldest = NULL; - content_.RemoveOldest(oldest); - - assert(oldest != NULL); - delete oldest; - } - - assert(maxSize_ == 0 || - content_.GetSize() < maxSize_); - - content_.Add(transactionUid, protection.release()); - } - - - StorageCommitmentReports::Accessor::Accessor(StorageCommitmentReports& that, - const std::string& transactionUid) : - lock_(that.mutex_), - transactionUid_(transactionUid) - { - if (that.content_.Contains(transactionUid, report_)) - { - that.content_.MakeMostRecent(transactionUid); - } - else - { - report_ = NULL; - } - } - - const StorageCommitmentReports::Report& - StorageCommitmentReports::Accessor::GetReport() const - { - if (report_ == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return *report_; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/OrthancServer/StorageCommitmentReports.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,147 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "../Core/Cache/LeastRecentlyUsedIndex.h" - -namespace Orthanc -{ - class StorageCommitmentReports - { - public: - class Report : public boost::noncopyable - { - public: - enum Status - { - Status_Success, - Status_Failure, - Status_Pending - }; - - private: - struct Success - { - std::string sopClassUid_; - std::string sopInstanceUid_; - }; - - struct Failure - { - std::string sopClassUid_; - std::string sopInstanceUid_; - StorageCommitmentFailureReason reason_; - }; - - bool isComplete_; - std::list success_; - std::list failures_; - std::string remoteAet_; - - public: - Report(const std::string& remoteAet) : - isComplete_(false), - remoteAet_(remoteAet) - { - } - - const std::string& GetRemoteAet() const - { - return remoteAet_; - } - - void MarkAsComplete(); - - void AddSuccess(const std::string& sopClassUid, - const std::string& sopInstanceUid); - - void AddFailure(const std::string& sopClassUid, - const std::string& sopInstanceUid, - StorageCommitmentFailureReason reason); - - Status GetStatus() const; - - void Format(Json::Value& json) const; - - void GetSuccessSopInstanceUids(std::vector& target) const; - }; - - private: - typedef LeastRecentlyUsedIndex Content; - - boost::mutex mutex_; - Content content_; - size_t maxSize_; - - public: - StorageCommitmentReports(size_t maxSize) : - maxSize_(maxSize) - { - } - - ~StorageCommitmentReports(); - - size_t GetMaxSize() const - { - return maxSize_; - } - - void Store(const std::string& transactionUid, - Report* report); // Takes ownership - - class Accessor : public boost::noncopyable - { - private: - boost::mutex::scoped_lock lock_; - std::string transactionUid_; - Report *report_; - - public: - Accessor(StorageCommitmentReports& that, - const std::string& transactionUid); - - const std::string& GetTransactionUid() const - { - return transactionUid_; - } - - bool IsValid() const - { - return report_ != NULL; - } - - const Report& GetReport() const; - }; - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,3395 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#include "OrthancPluginCppWrapper.h" - -#include -#include -#include -#include -#include - - -#if !ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0) -static const OrthancPluginErrorCode OrthancPluginErrorCode_NullPointer = OrthancPluginErrorCode_Plugin; -#endif - - -namespace OrthancPlugins -{ - static OrthancPluginContext* globalContext_ = NULL; - - - void SetGlobalContext(OrthancPluginContext* context) - { - if (context == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(NullPointer); - } - else if (globalContext_ == NULL) - { - globalContext_ = context; - } - else - { - ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); - } - } - - - bool HasGlobalContext() - { - return globalContext_ != NULL; - } - - - OrthancPluginContext* GetGlobalContext() - { - if (globalContext_ == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); - } - else - { - return globalContext_; - } - } - - - void MemoryBuffer::Check(OrthancPluginErrorCode code) - { - if (code != OrthancPluginErrorCode_Success) - { - // Prevent using garbage information - buffer_.data = NULL; - buffer_.size = 0; - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); - } - } - - - bool MemoryBuffer::CheckHttp(OrthancPluginErrorCode code) - { - if (code != OrthancPluginErrorCode_Success) - { - // Prevent using garbage information - buffer_.data = NULL; - buffer_.size = 0; - } - - if (code == OrthancPluginErrorCode_Success) - { - return true; - } - else if (code == OrthancPluginErrorCode_UnknownResource || - code == OrthancPluginErrorCode_InexistentItem) - { - return false; - } - else - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); - } - } - - - MemoryBuffer::MemoryBuffer() - { - buffer_.data = NULL; - buffer_.size = 0; - } - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - MemoryBuffer::MemoryBuffer(const void* buffer, - size_t size) - { - uint32_t s = static_cast(size); - if (static_cast(s) != size) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory); - } - else if (OrthancPluginCreateMemoryBuffer(GetGlobalContext(), &buffer_, s) != - OrthancPluginErrorCode_Success) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory); - } - else - { - memcpy(buffer_.data, buffer, size); - } - } -#endif - - - void MemoryBuffer::Clear() - { - if (buffer_.data != NULL) - { - OrthancPluginFreeMemoryBuffer(GetGlobalContext(), &buffer_); - buffer_.data = NULL; - buffer_.size = 0; - } - } - - - void MemoryBuffer::Assign(OrthancPluginMemoryBuffer& other) - { - Clear(); - - buffer_.data = other.data; - buffer_.size = other.size; - - other.data = NULL; - other.size = 0; - } - - - void MemoryBuffer::Swap(MemoryBuffer& other) - { - std::swap(buffer_.data, other.buffer_.data); - std::swap(buffer_.size, other.buffer_.size); - } - - - OrthancPluginMemoryBuffer MemoryBuffer::Release() - { - OrthancPluginMemoryBuffer result = buffer_; - - buffer_.data = NULL; - buffer_.size = 0; - - return result; - } - - - void MemoryBuffer::ToString(std::string& target) const - { - if (buffer_.size == 0) - { - target.clear(); - } - else - { - target.assign(reinterpret_cast(buffer_.data), buffer_.size); - } - } - - - void MemoryBuffer::ToJson(Json::Value& target) const - { - if (buffer_.data == NULL || - buffer_.size == 0) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - const char* tmp = reinterpret_cast(buffer_.data); - - Json::Reader reader; - if (!reader.parse(tmp, tmp + buffer_.size, target)) - { - LogError("Cannot convert some memory buffer to JSON"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - } - - - bool MemoryBuffer::RestApiGet(const std::string& uri, - bool applyPlugins) - { - Clear(); - - if (applyPlugins) - { - return CheckHttp(OrthancPluginRestApiGetAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str())); - } - else - { - return CheckHttp(OrthancPluginRestApiGet(GetGlobalContext(), &buffer_, uri.c_str())); - } - } - - bool MemoryBuffer::RestApiGet(const std::string& uri, - const std::map& httpHeaders, - bool applyPlugins) - { - Clear(); - - std::vector headersKeys; - std::vector headersValues; - - for (std::map::const_iterator - it = httpHeaders.begin(); it != httpHeaders.end(); it++) - { - headersKeys.push_back(it->first.c_str()); - headersValues.push_back(it->second.c_str()); - } - - return CheckHttp(OrthancPluginRestApiGet2( - GetGlobalContext(), &buffer_, uri.c_str(), httpHeaders.size(), - (headersKeys.empty() ? NULL : &headersKeys[0]), - (headersValues.empty() ? NULL : &headersValues[0]), applyPlugins)); - } - - bool MemoryBuffer::RestApiPost(const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins) - { - Clear(); - - // Cast for compatibility with Orthanc SDK <= 1.5.6 - const char* b = reinterpret_cast(body); - - if (applyPlugins) - { - return CheckHttp(OrthancPluginRestApiPostAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); - } - else - { - return CheckHttp(OrthancPluginRestApiPost(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); - } - } - - - bool MemoryBuffer::RestApiPut(const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins) - { - Clear(); - - // Cast for compatibility with Orthanc SDK <= 1.5.6 - const char* b = reinterpret_cast(body); - - if (applyPlugins) - { - return CheckHttp(OrthancPluginRestApiPutAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); - } - else - { - return CheckHttp(OrthancPluginRestApiPut(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); - } - } - - - bool MemoryBuffer::RestApiPost(const std::string& uri, - const Json::Value& body, - bool applyPlugins) - { - Json::FastWriter writer; - return RestApiPost(uri, writer.write(body), applyPlugins); - } - - - bool MemoryBuffer::RestApiPut(const std::string& uri, - const Json::Value& body, - bool applyPlugins) - { - Json::FastWriter writer; - return RestApiPut(uri, writer.write(body), applyPlugins); - } - - - void MemoryBuffer::CreateDicom(const Json::Value& tags, - OrthancPluginCreateDicomFlags flags) - { - Clear(); - - Json::FastWriter writer; - std::string s = writer.write(tags); - - Check(OrthancPluginCreateDicom(GetGlobalContext(), &buffer_, s.c_str(), NULL, flags)); - } - - void MemoryBuffer::CreateDicom(const Json::Value& tags, - const OrthancImage& pixelData, - OrthancPluginCreateDicomFlags flags) - { - Clear(); - - Json::FastWriter writer; - std::string s = writer.write(tags); - - Check(OrthancPluginCreateDicom(GetGlobalContext(), &buffer_, s.c_str(), pixelData.GetObject(), flags)); - } - - - void MemoryBuffer::ReadFile(const std::string& path) - { - Clear(); - Check(OrthancPluginReadFile(GetGlobalContext(), &buffer_, path.c_str())); - } - - - void MemoryBuffer::GetDicomQuery(const OrthancPluginWorklistQuery* query) - { - Clear(); - Check(OrthancPluginWorklistGetDicomQuery(GetGlobalContext(), &buffer_, query)); - } - - - void OrthancString::Assign(char* str) - { - Clear(); - - if (str != NULL) - { - str_ = str; - } - } - - - void OrthancString::Clear() - { - if (str_ != NULL) - { - OrthancPluginFreeString(GetGlobalContext(), str_); - str_ = NULL; - } - } - - - void OrthancString::ToString(std::string& target) const - { - if (str_ == NULL) - { - target.clear(); - } - else - { - target.assign(str_); - } - } - - - void OrthancString::ToJson(Json::Value& target) const - { - if (str_ == NULL) - { - LogError("Cannot convert an empty memory buffer to JSON"); - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - Json::Reader reader; - if (!reader.parse(str_, target)) - { - LogError("Cannot convert some memory buffer to JSON"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - } - - - void MemoryBuffer::DicomToJson(Json::Value& target, - OrthancPluginDicomToJsonFormat format, - OrthancPluginDicomToJsonFlags flags, - uint32_t maxStringLength) - { - OrthancString str; - str.Assign(OrthancPluginDicomBufferToJson - (GetGlobalContext(), GetData(), GetSize(), format, flags, maxStringLength)); - str.ToJson(target); - } - - - bool MemoryBuffer::HttpGet(const std::string& url, - const std::string& username, - const std::string& password) - { - Clear(); - return CheckHttp(OrthancPluginHttpGet(GetGlobalContext(), &buffer_, url.c_str(), - username.empty() ? NULL : username.c_str(), - password.empty() ? NULL : password.c_str())); - } - - - bool MemoryBuffer::HttpPost(const std::string& url, - const std::string& body, - const std::string& username, - const std::string& password) - { - Clear(); - return CheckHttp(OrthancPluginHttpPost(GetGlobalContext(), &buffer_, url.c_str(), - body.c_str(), body.size(), - username.empty() ? NULL : username.c_str(), - password.empty() ? NULL : password.c_str())); - } - - - bool MemoryBuffer::HttpPut(const std::string& url, - const std::string& body, - const std::string& username, - const std::string& password) - { - Clear(); - return CheckHttp(OrthancPluginHttpPut(GetGlobalContext(), &buffer_, url.c_str(), - body.empty() ? NULL : body.c_str(), - body.size(), - username.empty() ? NULL : username.c_str(), - password.empty() ? NULL : password.c_str())); - } - - - void MemoryBuffer::GetDicomInstance(const std::string& instanceId) - { - Clear(); - Check(OrthancPluginGetDicomForInstance(GetGlobalContext(), &buffer_, instanceId.c_str())); - } - - - bool HttpDelete(const std::string& url, - const std::string& username, - const std::string& password) - { - OrthancPluginErrorCode error = OrthancPluginHttpDelete - (GetGlobalContext(), url.c_str(), - username.empty() ? NULL : username.c_str(), - password.empty() ? NULL : password.c_str()); - - if (error == OrthancPluginErrorCode_Success) - { - return true; - } - else if (error == OrthancPluginErrorCode_UnknownResource || - error == OrthancPluginErrorCode_InexistentItem) - { - return false; - } - else - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); - } - } - - - void LogError(const std::string& message) - { - if (HasGlobalContext()) - { - OrthancPluginLogError(GetGlobalContext(), message.c_str()); - } - } - - - void LogWarning(const std::string& message) - { - if (HasGlobalContext()) - { - OrthancPluginLogWarning(GetGlobalContext(), message.c_str()); - } - } - - - void LogInfo(const std::string& message) - { - if (HasGlobalContext()) - { - OrthancPluginLogInfo(GetGlobalContext(), message.c_str()); - } - } - - - void OrthancConfiguration::LoadConfiguration() - { - OrthancString str; - str.Assign(OrthancPluginGetConfiguration(GetGlobalContext())); - - if (str.GetContent() == NULL) - { - LogError("Cannot access the Orthanc configuration"); - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - str.ToJson(configuration_); - - if (configuration_.type() != Json::objectValue) - { - LogError("Unable to read the Orthanc configuration"); - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - } - - - OrthancConfiguration::OrthancConfiguration() - { - LoadConfiguration(); - } - - - OrthancConfiguration::OrthancConfiguration(bool loadConfiguration) - { - if (loadConfiguration) - { - LoadConfiguration(); - } - else - { - configuration_ = Json::objectValue; - } - } - - - std::string OrthancConfiguration::GetPath(const std::string& key) const - { - if (path_.empty()) - { - return key; - } - else - { - return path_ + "." + key; - } - } - - - bool OrthancConfiguration::IsSection(const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - return (configuration_.isMember(key) && - configuration_[key].type() == Json::objectValue); - } - - - void OrthancConfiguration::GetSection(OrthancConfiguration& target, - const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - target.path_ = GetPath(key); - - if (!configuration_.isMember(key)) - { - target.configuration_ = Json::objectValue; - } - else - { - if (configuration_[key].type() != Json::objectValue) - { - LogError("The configuration section \"" + target.path_ + - "\" is not an associative array as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - - target.configuration_ = configuration_[key]; - } - } - - - bool OrthancConfiguration::LookupStringValue(std::string& target, - const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - if (!configuration_.isMember(key)) - { - return false; - } - - if (configuration_[key].type() != Json::stringValue) - { - LogError("The configuration option \"" + GetPath(key) + - "\" is not a string as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - - target = configuration_[key].asString(); - return true; - } - - - bool OrthancConfiguration::LookupIntegerValue(int& target, - const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - if (!configuration_.isMember(key)) - { - return false; - } - - switch (configuration_[key].type()) - { - case Json::intValue: - target = configuration_[key].asInt(); - return true; - - case Json::uintValue: - target = configuration_[key].asUInt(); - return true; - - default: - LogError("The configuration option \"" + GetPath(key) + - "\" is not an integer as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - } - - - bool OrthancConfiguration::LookupUnsignedIntegerValue(unsigned int& target, - const std::string& key) const - { - int tmp; - if (!LookupIntegerValue(tmp, key)) - { - return false; - } - - if (tmp < 0) - { - LogError("The configuration option \"" + GetPath(key) + - "\" is not a positive integer as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - else - { - target = static_cast(tmp); - return true; - } - } - - - bool OrthancConfiguration::LookupBooleanValue(bool& target, - const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - if (!configuration_.isMember(key)) - { - return false; - } - - if (configuration_[key].type() != Json::booleanValue) - { - LogError("The configuration option \"" + GetPath(key) + - "\" is not a Boolean as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - - target = configuration_[key].asBool(); - return true; - } - - - bool OrthancConfiguration::LookupFloatValue(float& target, - const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - if (!configuration_.isMember(key)) - { - return false; - } - - switch (configuration_[key].type()) - { - case Json::realValue: - target = configuration_[key].asFloat(); - return true; - - case Json::intValue: - target = static_cast(configuration_[key].asInt()); - return true; - - case Json::uintValue: - target = static_cast(configuration_[key].asUInt()); - return true; - - default: - LogError("The configuration option \"" + GetPath(key) + - "\" is not an integer as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - } - - - bool OrthancConfiguration::LookupListOfStrings(std::list& target, - const std::string& key, - bool allowSingleString) const - { - assert(configuration_.type() == Json::objectValue); - - target.clear(); - - if (!configuration_.isMember(key)) - { - return false; - } - - switch (configuration_[key].type()) - { - case Json::arrayValue: - { - bool ok = true; - - for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++) - { - if (configuration_[key][i].type() == Json::stringValue) - { - target.push_back(configuration_[key][i].asString()); - } - else - { - ok = false; - } - } - - if (ok) - { - return true; - } - - break; - } - - case Json::stringValue: - if (allowSingleString) - { - target.push_back(configuration_[key].asString()); - return true; - } - - break; - - default: - break; - } - - LogError("The configuration option \"" + GetPath(key) + - "\" is not a list of strings as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - - - bool OrthancConfiguration::LookupSetOfStrings(std::set& target, - const std::string& key, - bool allowSingleString) const - { - std::list lst; - - if (LookupListOfStrings(lst, key, allowSingleString)) - { - target.clear(); - - for (std::list::const_iterator - it = lst.begin(); it != lst.end(); ++it) - { - target.insert(*it); - } - - return true; - } - else - { - return false; - } - } - - - std::string OrthancConfiguration::GetStringValue(const std::string& key, - const std::string& defaultValue) const - { - std::string tmp; - if (LookupStringValue(tmp, key)) - { - return tmp; - } - else - { - return defaultValue; - } - } - - - int OrthancConfiguration::GetIntegerValue(const std::string& key, - int defaultValue) const - { - int tmp; - if (LookupIntegerValue(tmp, key)) - { - return tmp; - } - else - { - return defaultValue; - } - } - - - unsigned int OrthancConfiguration::GetUnsignedIntegerValue(const std::string& key, - unsigned int defaultValue) const - { - unsigned int tmp; - if (LookupUnsignedIntegerValue(tmp, key)) - { - return tmp; - } - else - { - return defaultValue; - } - } - - - bool OrthancConfiguration::GetBooleanValue(const std::string& key, - bool defaultValue) const - { - bool tmp; - if (LookupBooleanValue(tmp, key)) - { - return tmp; - } - else - { - return defaultValue; - } - } - - - float OrthancConfiguration::GetFloatValue(const std::string& key, - float defaultValue) const - { - float tmp; - if (LookupFloatValue(tmp, key)) - { - return tmp; - } - else - { - return defaultValue; - } - } - - - void OrthancConfiguration::GetDictionary(std::map& target, - const std::string& key) const - { - assert(configuration_.type() == Json::objectValue); - - target.clear(); - - if (!configuration_.isMember(key)) - { - return; - } - - if (configuration_[key].type() != Json::objectValue) - { - LogError("The configuration option \"" + GetPath(key) + - "\" is not a string as expected"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - - Json::Value::Members members = configuration_[key].getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& value = configuration_[key][members[i]]; - - if (value.type() == Json::stringValue) - { - target[members[i]] = value.asString(); - } - else - { - LogError("The configuration option \"" + GetPath(key) + - "\" is not a dictionary mapping strings to strings"); - - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - } - } - - - void OrthancImage::Clear() - { - if (image_ != NULL) - { - OrthancPluginFreeImage(GetGlobalContext(), image_); - image_ = NULL; - } - } - - - void OrthancImage::CheckImageAvailable() const - { - if (image_ == NULL) - { - LogError("Trying to access a NULL image"); - ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); - } - } - - - OrthancImage::OrthancImage() : - image_(NULL) - { - } - - - OrthancImage::OrthancImage(OrthancPluginImage* image) : - image_(image) - { - } - - - OrthancImage::OrthancImage(OrthancPluginPixelFormat format, - uint32_t width, - uint32_t height) - { - image_ = OrthancPluginCreateImage(GetGlobalContext(), format, width, height); - - if (image_ == NULL) - { - LogError("Cannot create an image"); - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - } - - - OrthancImage::OrthancImage(OrthancPluginPixelFormat format, - uint32_t width, - uint32_t height, - uint32_t pitch, - void* buffer) - { - image_ = OrthancPluginCreateImageAccessor - (GetGlobalContext(), format, width, height, pitch, buffer); - - if (image_ == NULL) - { - LogError("Cannot create an image accessor"); - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - } - - void OrthancImage::UncompressPngImage(const void* data, - size_t size) - { - Clear(); - - image_ = OrthancPluginUncompressImage(GetGlobalContext(), data, size, OrthancPluginImageFormat_Png); - - if (image_ == NULL) - { - LogError("Cannot uncompress a PNG image"); - ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); - } - } - - - void OrthancImage::UncompressJpegImage(const void* data, - size_t size) - { - Clear(); - image_ = OrthancPluginUncompressImage(GetGlobalContext(), data, size, OrthancPluginImageFormat_Jpeg); - if (image_ == NULL) - { - LogError("Cannot uncompress a JPEG image"); - ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); - } - } - - - void OrthancImage::DecodeDicomImage(const void* data, - size_t size, - unsigned int frame) - { - Clear(); - image_ = OrthancPluginDecodeDicomImage(GetGlobalContext(), data, size, frame); - if (image_ == NULL) - { - LogError("Cannot uncompress a DICOM image"); - ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); - } - } - - - OrthancPluginPixelFormat OrthancImage::GetPixelFormat() const - { - CheckImageAvailable(); - return OrthancPluginGetImagePixelFormat(GetGlobalContext(), image_); - } - - - unsigned int OrthancImage::GetWidth() const - { - CheckImageAvailable(); - return OrthancPluginGetImageWidth(GetGlobalContext(), image_); - } - - - unsigned int OrthancImage::GetHeight() const - { - CheckImageAvailable(); - return OrthancPluginGetImageHeight(GetGlobalContext(), image_); - } - - - unsigned int OrthancImage::GetPitch() const - { - CheckImageAvailable(); - return OrthancPluginGetImagePitch(GetGlobalContext(), image_); - } - - - void* OrthancImage::GetBuffer() const - { - CheckImageAvailable(); - return OrthancPluginGetImageBuffer(GetGlobalContext(), image_); - } - - - void OrthancImage::CompressPngImage(MemoryBuffer& target) const - { - CheckImageAvailable(); - - OrthancPlugins::MemoryBuffer answer; - OrthancPluginCompressPngImage(GetGlobalContext(), *answer, GetPixelFormat(), - GetWidth(), GetHeight(), GetPitch(), GetBuffer()); - - target.Swap(answer); - } - - - void OrthancImage::CompressJpegImage(MemoryBuffer& target, - uint8_t quality) const - { - CheckImageAvailable(); - - OrthancPlugins::MemoryBuffer answer; - OrthancPluginCompressJpegImage(GetGlobalContext(), *answer, GetPixelFormat(), - GetWidth(), GetHeight(), GetPitch(), GetBuffer(), quality); - - target.Swap(answer); - } - - - void OrthancImage::AnswerPngImage(OrthancPluginRestOutput* output) const - { - CheckImageAvailable(); - OrthancPluginCompressAndAnswerPngImage(GetGlobalContext(), output, GetPixelFormat(), - GetWidth(), GetHeight(), GetPitch(), GetBuffer()); - } - - - void OrthancImage::AnswerJpegImage(OrthancPluginRestOutput* output, - uint8_t quality) const - { - CheckImageAvailable(); - OrthancPluginCompressAndAnswerJpegImage(GetGlobalContext(), output, GetPixelFormat(), - GetWidth(), GetHeight(), GetPitch(), GetBuffer(), quality); - } - - - OrthancPluginImage* OrthancImage::Release() - { - CheckImageAvailable(); - OrthancPluginImage* tmp = image_; - image_ = NULL; - return tmp; - } - - -#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 - FindMatcher::FindMatcher(const OrthancPluginWorklistQuery* worklist) : - matcher_(NULL), - worklist_(worklist) - { - if (worklist_ == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); - } - } - - - void FindMatcher::SetupDicom(const void* query, - uint32_t size) - { - worklist_ = NULL; - - matcher_ = OrthancPluginCreateFindMatcher(GetGlobalContext(), query, size); - if (matcher_ == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - } - - - FindMatcher::~FindMatcher() - { - // The "worklist_" field - - if (matcher_ != NULL) - { - OrthancPluginFreeFindMatcher(GetGlobalContext(), matcher_); - } - } - - - - bool FindMatcher::IsMatch(const void* dicom, - uint32_t size) const - { - int32_t result; - - if (matcher_ != NULL) - { - result = OrthancPluginFindMatcherIsMatch(GetGlobalContext(), matcher_, dicom, size); - } - else if (worklist_ != NULL) - { - result = OrthancPluginWorklistIsMatch(GetGlobalContext(), worklist_, dicom, size); - } - else - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - if (result == 0) - { - return false; - } - else if (result == 1) - { - return true; - } - else - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - } - -#endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */ - - void AnswerJson(const Json::Value& value, - OrthancPluginRestOutput* output - ) - { - Json::StyledWriter writer; - std::string bodyString = writer.write(value); - - OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json"); - } - - void AnswerString(const std::string& answer, - const char* mimeType, - OrthancPluginRestOutput* output - ) - { - OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType); - } - - void AnswerHttpError(uint16_t httpError, OrthancPluginRestOutput *output) - { - OrthancPluginSendHttpStatusCode(GetGlobalContext(), output, httpError); - } - - void AnswerMethodNotAllowed(OrthancPluginRestOutput *output, const char* allowedMethods) - { - OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowedMethods); - } - - bool RestApiGetString(std::string& result, - const std::string& uri, - bool applyPlugins) - { - MemoryBuffer answer; - if (!answer.RestApiGet(uri, applyPlugins)) - { - return false; - } - else - { - answer.ToString(result); - return true; - } - } - - bool RestApiGetString(std::string& result, - const std::string& uri, - const std::map& httpHeaders, - bool applyPlugins) - { - MemoryBuffer answer; - if (!answer.RestApiGet(uri, httpHeaders, applyPlugins)) - { - return false; - } - else - { - answer.ToString(result); - return true; - } - } - - - - bool RestApiGet(Json::Value& result, - const std::string& uri, - bool applyPlugins) - { - MemoryBuffer answer; - - if (!answer.RestApiGet(uri, applyPlugins)) - { - return false; - } - else - { - if (!answer.IsEmpty()) - { - answer.ToJson(result); - } - return true; - } - } - - - bool RestApiPost(std::string& result, - const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins) - { - MemoryBuffer answer; - - if (!answer.RestApiPost(uri, body, bodySize, applyPlugins)) - { - return false; - } - else - { - if (!answer.IsEmpty()) - { - result.assign(answer.GetData(), answer.GetSize()); - } - return true; - } - } - - - bool RestApiPost(Json::Value& result, - const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins) - { - MemoryBuffer answer; - - if (!answer.RestApiPost(uri, body, bodySize, applyPlugins)) - { - return false; - } - else - { - if (!answer.IsEmpty()) - { - answer.ToJson(result); - } - return true; - } - } - - - bool RestApiPost(Json::Value& result, - const std::string& uri, - const Json::Value& body, - bool applyPlugins) - { - Json::FastWriter writer; - return RestApiPost(result, uri, writer.write(body), applyPlugins); - } - - - bool RestApiPut(Json::Value& result, - const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins) - { - MemoryBuffer answer; - - if (!answer.RestApiPut(uri, body, bodySize, applyPlugins)) - { - return false; - } - else - { - if (!answer.IsEmpty()) // i.e, on a PUT to metadata/..., orthanc returns an empty response - { - answer.ToJson(result); - } - return true; - } - } - - - bool RestApiPut(Json::Value& result, - const std::string& uri, - const Json::Value& body, - bool applyPlugins) - { - Json::FastWriter writer; - return RestApiPut(result, uri, writer.write(body), applyPlugins); - } - - - bool RestApiDelete(const std::string& uri, - bool applyPlugins) - { - OrthancPluginErrorCode error; - - if (applyPlugins) - { - error = OrthancPluginRestApiDeleteAfterPlugins(GetGlobalContext(), uri.c_str()); - } - else - { - error = OrthancPluginRestApiDelete(GetGlobalContext(), uri.c_str()); - } - - if (error == OrthancPluginErrorCode_Success) - { - return true; - } - else if (error == OrthancPluginErrorCode_UnknownResource || - error == OrthancPluginErrorCode_InexistentItem) - { - return false; - } - else - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); - } - } - - - void ReportMinimalOrthancVersion(unsigned int major, - unsigned int minor, - unsigned int revision) - { - LogError("Your version of the Orthanc core (" + - std::string(GetGlobalContext()->orthancVersion) + - ") is too old to run this plugin (version " + - boost::lexical_cast(major) + "." + - boost::lexical_cast(minor) + "." + - boost::lexical_cast(revision) + - " is required)"); - } - - - bool CheckMinimalOrthancVersion(unsigned int major, - unsigned int minor, - unsigned int revision) - { - if (!HasGlobalContext()) - { - LogError("Bad Orthanc context in the plugin"); - return false; - } - - if (!strcmp(GetGlobalContext()->orthancVersion, "mainline")) - { - // Assume compatibility with the mainline - return true; - } - - // Parse the version of the Orthanc core - int aa, bb, cc; - if ( -#ifdef _MSC_VER - sscanf_s -#else - sscanf -#endif - (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 || - aa < 0 || - bb < 0 || - cc < 0) - { - return false; - } - - unsigned int a = static_cast(aa); - unsigned int b = static_cast(bb); - unsigned int c = static_cast(cc); - - // Check the major version number - - if (a > major) - { - return true; - } - - if (a < major) - { - return false; - } - - - // Check the minor version number - assert(a == major); - - if (b > minor) - { - return true; - } - - if (b < minor) - { - return false; - } - - // Check the patch level version number - assert(a == major && b == minor); - - if (c >= revision) - { - return true; - } - else - { - return false; - } - } - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) - const char* AutodetectMimeType(const std::string& path) - { - const char* mime = OrthancPluginAutodetectMimeType(GetGlobalContext(), path.c_str()); - - if (mime == NULL) - { - // Should never happen, just for safety - return "application/octet-stream"; - } - else - { - return mime; - } - } -#endif - - -#if HAS_ORTHANC_PLUGIN_PEERS == 1 - size_t OrthancPeers::GetPeerIndex(const std::string& name) const - { - size_t index; - if (LookupName(index, name)) - { - return index; - } - else - { - LogError("Inexistent peer: " + name); - ORTHANC_PLUGINS_THROW_EXCEPTION(UnknownResource); - } - } - - - OrthancPeers::OrthancPeers() : - peers_(NULL), - timeout_(0) - { - peers_ = OrthancPluginGetPeers(GetGlobalContext()); - - if (peers_ == NULL) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); - } - - uint32_t count = OrthancPluginGetPeersCount(GetGlobalContext(), peers_); - - for (uint32_t i = 0; i < count; i++) - { - const char* name = OrthancPluginGetPeerName(GetGlobalContext(), peers_, i); - if (name == NULL) - { - OrthancPluginFreePeers(GetGlobalContext(), peers_); - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); - } - - index_[name] = i; - } - } - - - OrthancPeers::~OrthancPeers() - { - if (peers_ != NULL) - { - OrthancPluginFreePeers(GetGlobalContext(), peers_); - } - } - - - bool OrthancPeers::LookupName(size_t& target, - const std::string& name) const - { - Index::const_iterator found = index_.find(name); - - if (found == index_.end()) - { - return false; - } - else - { - target = found->second; - return true; - } - } - - - std::string OrthancPeers::GetPeerName(size_t index) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - else - { - const char* s = OrthancPluginGetPeerName(GetGlobalContext(), peers_, static_cast(index)); - if (s == NULL) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); - } - else - { - return s; - } - } - } - - - std::string OrthancPeers::GetPeerUrl(size_t index) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - else - { - const char* s = OrthancPluginGetPeerUrl(GetGlobalContext(), peers_, static_cast(index)); - if (s == NULL) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); - } - else - { - return s; - } - } - } - - - std::string OrthancPeers::GetPeerUrl(const std::string& name) const - { - return GetPeerUrl(GetPeerIndex(name)); - } - - - bool OrthancPeers::LookupUserProperty(std::string& value, - size_t index, - const std::string& key) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - else - { - const char* s = OrthancPluginGetPeerUserProperty(GetGlobalContext(), peers_, static_cast(index), key.c_str()); - if (s == NULL) - { - return false; - } - else - { - value.assign(s); - return true; - } - } - } - - - bool OrthancPeers::LookupUserProperty(std::string& value, - const std::string& peer, - const std::string& key) const - { - return LookupUserProperty(value, GetPeerIndex(peer), key); - } - - - bool OrthancPeers::DoGet(MemoryBuffer& target, - size_t index, - const std::string& uri) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - - OrthancPlugins::MemoryBuffer answer; - uint16_t status; - OrthancPluginErrorCode code = OrthancPluginCallPeerApi - (GetGlobalContext(), *answer, NULL, &status, peers_, - static_cast(index), OrthancPluginHttpMethod_Get, uri.c_str(), - 0, NULL, NULL, NULL, 0, timeout_); - - if (code == OrthancPluginErrorCode_Success) - { - target.Swap(answer); - return (status == 200); - } - else - { - return false; - } - } - - - bool OrthancPeers::DoGet(MemoryBuffer& target, - const std::string& name, - const std::string& uri) const - { - size_t index; - return (LookupName(index, name) && - DoGet(target, index, uri)); - } - - - bool OrthancPeers::DoGet(Json::Value& target, - size_t index, - const std::string& uri) const - { - MemoryBuffer buffer; - - if (DoGet(buffer, index, uri)) - { - buffer.ToJson(target); - return true; - } - else - { - return false; - } - } - - - bool OrthancPeers::DoGet(Json::Value& target, - const std::string& name, - const std::string& uri) const - { - MemoryBuffer buffer; - - if (DoGet(buffer, name, uri)) - { - buffer.ToJson(target); - return true; - } - else - { - return false; - } - } - - - bool OrthancPeers::DoPost(MemoryBuffer& target, - const std::string& name, - const std::string& uri, - const std::string& body) const - { - size_t index; - return (LookupName(index, name) && - DoPost(target, index, uri, body)); - } - - - bool OrthancPeers::DoPost(Json::Value& target, - size_t index, - const std::string& uri, - const std::string& body) const - { - MemoryBuffer buffer; - - if (DoPost(buffer, index, uri, body)) - { - buffer.ToJson(target); - return true; - } - else - { - return false; - } - } - - - bool OrthancPeers::DoPost(Json::Value& target, - const std::string& name, - const std::string& uri, - const std::string& body) const - { - MemoryBuffer buffer; - - if (DoPost(buffer, name, uri, body)) - { - buffer.ToJson(target); - return true; - } - else - { - return false; - } - } - - - bool OrthancPeers::DoPost(MemoryBuffer& target, - size_t index, - const std::string& uri, - const std::string& body) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - - OrthancPlugins::MemoryBuffer answer; - uint16_t status; - OrthancPluginErrorCode code = OrthancPluginCallPeerApi - (GetGlobalContext(), *answer, NULL, &status, peers_, - static_cast(index), OrthancPluginHttpMethod_Post, uri.c_str(), - 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); - - if (code == OrthancPluginErrorCode_Success) - { - target.Swap(answer); - return (status == 200); - } - else - { - return false; - } - } - - - bool OrthancPeers::DoPut(size_t index, - const std::string& uri, - const std::string& body) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - - OrthancPlugins::MemoryBuffer answer; - uint16_t status; - OrthancPluginErrorCode code = OrthancPluginCallPeerApi - (GetGlobalContext(), *answer, NULL, &status, peers_, - static_cast(index), OrthancPluginHttpMethod_Put, uri.c_str(), - 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); - - if (code == OrthancPluginErrorCode_Success) - { - return (status == 200); - } - else - { - return false; - } - } - - - bool OrthancPeers::DoPut(const std::string& name, - const std::string& uri, - const std::string& body) const - { - size_t index; - return (LookupName(index, name) && - DoPut(index, uri, body)); - } - - - bool OrthancPeers::DoDelete(size_t index, - const std::string& uri) const - { - if (index >= index_.size()) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - - OrthancPlugins::MemoryBuffer answer; - uint16_t status; - OrthancPluginErrorCode code = OrthancPluginCallPeerApi - (GetGlobalContext(), *answer, NULL, &status, peers_, - static_cast(index), OrthancPluginHttpMethod_Delete, uri.c_str(), - 0, NULL, NULL, NULL, 0, timeout_); - - if (code == OrthancPluginErrorCode_Success) - { - return (status == 200); - } - else - { - return false; - } - } - - - bool OrthancPeers::DoDelete(const std::string& name, - const std::string& uri) const - { - size_t index; - return (LookupName(index, name) && - DoDelete(index, uri)); - } -#endif - - - - - - /****************************************************************** - ** JOBS - ******************************************************************/ - -#if HAS_ORTHANC_PLUGIN_JOB == 1 - void OrthancJob::CallbackFinalize(void* job) - { - if (job != NULL) - { - delete reinterpret_cast(job); - } - } - - - float OrthancJob::CallbackGetProgress(void* job) - { - assert(job != NULL); - - try - { - return reinterpret_cast(job)->progress_; - } - catch (...) - { - return 0; - } - } - - - const char* OrthancJob::CallbackGetContent(void* job) - { - assert(job != NULL); - - try - { - return reinterpret_cast(job)->content_.c_str(); - } - catch (...) - { - return 0; - } - } - - - const char* OrthancJob::CallbackGetSerialized(void* job) - { - assert(job != NULL); - - try - { - const OrthancJob& tmp = *reinterpret_cast(job); - - if (tmp.hasSerialized_) - { - return tmp.serialized_.c_str(); - } - else - { - return NULL; - } - } - catch (...) - { - return 0; - } - } - - - OrthancPluginJobStepStatus OrthancJob::CallbackStep(void* job) - { - assert(job != NULL); - - try - { - return reinterpret_cast(job)->Step(); - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&) - { - return OrthancPluginJobStepStatus_Failure; - } - catch (...) - { - return OrthancPluginJobStepStatus_Failure; - } - } - - - OrthancPluginErrorCode OrthancJob::CallbackStop(void* job, - OrthancPluginJobStopReason reason) - { - assert(job != NULL); - - try - { - reinterpret_cast(job)->Stop(reason); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } - - - OrthancPluginErrorCode OrthancJob::CallbackReset(void* job) - { - assert(job != NULL); - - try - { - reinterpret_cast(job)->Reset(); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } - - - void OrthancJob::ClearContent() - { - Json::Value empty = Json::objectValue; - UpdateContent(empty); - } - - - void OrthancJob::UpdateContent(const Json::Value& content) - { - if (content.type() != Json::objectValue) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat); - } - else - { - Json::FastWriter writer; - content_ = writer.write(content); - } - } - - - void OrthancJob::ClearSerialized() - { - hasSerialized_ = false; - serialized_.clear(); - } - - - void OrthancJob::UpdateSerialized(const Json::Value& serialized) - { - if (serialized.type() != Json::objectValue) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat); - } - else - { - Json::FastWriter writer; - serialized_ = writer.write(serialized); - hasSerialized_ = true; - } - } - - - void OrthancJob::UpdateProgress(float progress) - { - if (progress < 0 || - progress > 1) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); - } - - progress_ = progress; - } - - - OrthancJob::OrthancJob(const std::string& jobType) : - jobType_(jobType), - progress_(0) - { - ClearContent(); - ClearSerialized(); - } - - - OrthancPluginJob* OrthancJob::Create(OrthancJob* job) - { - if (job == NULL) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); - } - - OrthancPluginJob* orthanc = OrthancPluginCreateJob( - GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(), - CallbackGetProgress, CallbackGetContent, CallbackGetSerialized, - CallbackStep, CallbackStop, CallbackReset); - - if (orthanc == NULL) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); - } - else - { - return orthanc; - } - } - - - std::string OrthancJob::Submit(OrthancJob* job, - int priority) - { - if (job == NULL) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); - } - - OrthancPluginJob* orthanc = Create(job); - - char* id = OrthancPluginSubmitJob(GetGlobalContext(), orthanc, priority); - - if (id == NULL) - { - LogError("Plugin cannot submit job"); - OrthancPluginFreeJob(GetGlobalContext(), orthanc); - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); - } - else - { - std::string tmp(id); - tmp.assign(id); - OrthancPluginFreeString(GetGlobalContext(), id); - - return tmp; - } - } - - - void OrthancJob::SubmitAndWait(Json::Value& result, - OrthancJob* job /* takes ownership */, - int priority) - { - std::string id = Submit(job, priority); - - for (;;) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - - Json::Value status; - if (!RestApiGet(status, "/jobs/" + id, false) || - !status.isMember("State") || - status["State"].type() != Json::stringValue) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InexistentItem); - } - - const std::string state = status["State"].asString(); - if (state == "Success") - { - if (status.isMember("Content")) - { - result = status["Content"]; - } - else - { - result = Json::objectValue; - } - - return; - } - else if (state == "Running") - { - continue; - } - else if (!status.isMember("ErrorCode") || - status["ErrorCode"].type() != Json::intValue) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InternalError); - } - else - { - if (!status.isMember("ErrorDescription") || - status["ErrorDescription"].type() != Json::stringValue) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(status["ErrorCode"].asInt()); - } - else - { -#if HAS_ORTHANC_EXCEPTION == 1 - throw Orthanc::OrthancException(static_cast(status["ErrorCode"].asInt()), - status["ErrorDescription"].asString()); -#else - LogError("Exception while executing the job: " + status["ErrorDescription"].asString()); - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(status["ErrorCode"].asInt()); -#endif - } - } - } - } - - - void OrthancJob::SubmitFromRestApiPost(OrthancPluginRestOutput* output, - const Json::Value& body, - OrthancJob* job) - { - static const char* KEY_SYNCHRONOUS = "Synchronous"; - static const char* KEY_ASYNCHRONOUS = "Asynchronous"; - static const char* KEY_PRIORITY = "Priority"; - - boost::movelib::unique_ptr protection(job); - - if (body.type() != Json::objectValue) - { -#if HAS_ORTHANC_EXCEPTION == 1 - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, - "Expected a JSON object in the body"); -#else - LogError("Expected a JSON object in the body"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); -#endif - } - - bool synchronous = true; - - if (body.isMember(KEY_SYNCHRONOUS)) - { - if (body[KEY_SYNCHRONOUS].type() != Json::booleanValue) - { -#if HAS_ORTHANC_EXCEPTION == 1 - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, - "Option \"" + std::string(KEY_SYNCHRONOUS) + - "\" must be Boolean"); -#else - LogError("Option \"" + std::string(KEY_SYNCHRONOUS) + "\" must be Boolean"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); -#endif - } - else - { - synchronous = body[KEY_SYNCHRONOUS].asBool(); - } - } - - if (body.isMember(KEY_ASYNCHRONOUS)) - { - if (body[KEY_ASYNCHRONOUS].type() != Json::booleanValue) - { -#if HAS_ORTHANC_EXCEPTION == 1 - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, - "Option \"" + std::string(KEY_ASYNCHRONOUS) + - "\" must be Boolean"); -#else - LogError("Option \"" + std::string(KEY_ASYNCHRONOUS) + "\" must be Boolean"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); -#endif - } - else - { - synchronous = !body[KEY_ASYNCHRONOUS].asBool(); - } - } - - int priority = 0; - - if (body.isMember(KEY_PRIORITY)) - { - if (body[KEY_PRIORITY].type() != Json::booleanValue) - { -#if HAS_ORTHANC_EXCEPTION == 1 - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, - "Option \"" + std::string(KEY_PRIORITY) + - "\" must be an integer"); -#else - LogError("Option \"" + std::string(KEY_PRIORITY) + "\" must be an integer"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); -#endif - } - else - { - priority = !body[KEY_PRIORITY].asInt(); - } - } - - Json::Value result; - - if (synchronous) - { - OrthancPlugins::OrthancJob::SubmitAndWait(result, protection.release(), priority); - } - else - { - std::string id = OrthancPlugins::OrthancJob::Submit(protection.release(), priority); - - result = Json::objectValue; - result["ID"] = id; - result["Path"] = "/jobs/" + id; - } - - std::string s = result.toStyledString(); - OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), - s.size(), "application/json"); - } - -#endif - - - - - /****************************************************************** - ** METRICS - ******************************************************************/ - -#if HAS_ORTHANC_PLUGIN_METRICS == 1 - MetricsTimer::MetricsTimer(const char* name) : - name_(name) - { - start_ = boost::posix_time::microsec_clock::universal_time(); - } - - MetricsTimer::~MetricsTimer() - { - const boost::posix_time::ptime stop = boost::posix_time::microsec_clock::universal_time(); - const boost::posix_time::time_duration diff = stop - start_; - OrthancPluginSetMetricsValue(GetGlobalContext(), name_.c_str(), static_cast(diff.total_milliseconds()), - OrthancPluginMetricsType_Timer); - } -#endif - - - - - /****************************************************************** - ** HTTP CLIENT - ******************************************************************/ - -#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 - class HttpClient::RequestBodyWrapper : public boost::noncopyable - { - private: - static RequestBodyWrapper& GetObject(void* body) - { - assert(body != NULL); - return *reinterpret_cast(body); - } - - IRequestBody& body_; - bool done_; - std::string chunk_; - - public: - RequestBodyWrapper(IRequestBody& body) : - body_(body), - done_(false) - { - } - - static uint8_t IsDone(void* body) - { - return GetObject(body).done_; - } - - static const void* GetChunkData(void* body) - { - return GetObject(body).chunk_.c_str(); - } - - static uint32_t GetChunkSize(void* body) - { - return static_cast(GetObject(body).chunk_.size()); - } - - static OrthancPluginErrorCode Next(void* body) - { - RequestBodyWrapper& that = GetObject(body); - - if (that.done_) - { - return OrthancPluginErrorCode_BadSequenceOfCalls; - } - else - { - try - { - that.done_ = !that.body_.ReadNextChunk(that.chunk_); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (...) - { - return OrthancPluginErrorCode_InternalError; - } - } - } - }; - - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - static OrthancPluginErrorCode AnswerAddHeaderCallback(void* answer, - const char* key, - const char* value) - { - assert(answer != NULL && key != NULL && value != NULL); - - try - { - reinterpret_cast(answer)->AddHeader(key, value); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } -#endif - - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - static OrthancPluginErrorCode AnswerAddChunkCallback(void* answer, - const void* data, - uint32_t size) - { - assert(answer != NULL); - - try - { - reinterpret_cast(answer)->AddChunk(data, size); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } -#endif - - - HttpClient::HttpClient() : - httpStatus_(0), - method_(OrthancPluginHttpMethod_Get), - timeout_(0), - pkcs11_(false), - chunkedBody_(NULL), - allowChunkedTransfers_(true) - { - } - - - void HttpClient::AddHeaders(const HttpHeaders& headers) - { - for (HttpHeaders::const_iterator it = headers.begin(); - it != headers.end(); ++it) - { - headers_[it->first] = it->second; - } - } - - - void HttpClient::SetCredentials(const std::string& username, - const std::string& password) - { - username_ = username; - password_ = password; - } - - - void HttpClient::ClearCredentials() - { - username_.empty(); - password_.empty(); - } - - - void HttpClient::SetCertificate(const std::string& certificateFile, - const std::string& keyFile, - const std::string& keyPassword) - { - certificateFile_ = certificateFile; - certificateKeyFile_ = keyFile; - certificateKeyPassword_ = keyPassword; - } - - - void HttpClient::ClearCertificate() - { - certificateFile_.clear(); - certificateKeyFile_.clear(); - certificateKeyPassword_.clear(); - } - - - void HttpClient::ClearBody() - { - fullBody_.clear(); - chunkedBody_ = NULL; - } - - - void HttpClient::SwapBody(std::string& body) - { - fullBody_.swap(body); - chunkedBody_ = NULL; - } - - - void HttpClient::SetBody(const std::string& body) - { - fullBody_ = body; - chunkedBody_ = NULL; - } - - - void HttpClient::SetBody(IRequestBody& body) - { - fullBody_.clear(); - chunkedBody_ = &body; - } - - - namespace - { - class HeadersWrapper : public boost::noncopyable - { - private: - std::vector headersKeys_; - std::vector headersValues_; - - public: - HeadersWrapper(const HttpClient::HttpHeaders& headers) - { - headersKeys_.reserve(headers.size()); - headersValues_.reserve(headers.size()); - - for (HttpClient::HttpHeaders::const_iterator it = headers.begin(); it != headers.end(); ++it) - { - headersKeys_.push_back(it->first.c_str()); - headersValues_.push_back(it->second.c_str()); - } - } - - void AddStaticString(const char* key, - const char* value) - { - headersKeys_.push_back(key); - headersValues_.push_back(value); - } - - uint32_t GetCount() const - { - return headersKeys_.size(); - } - - const char* const* GetKeys() const - { - return headersKeys_.empty() ? NULL : &headersKeys_[0]; - } - - const char* const* GetValues() const - { - return headersValues_.empty() ? NULL : &headersValues_[0]; - } - }; - - - class MemoryRequestBody : public HttpClient::IRequestBody - { - private: - std::string body_; - bool done_; - - public: - MemoryRequestBody(const std::string& body) : - body_(body), - done_(false) - { - if (body_.empty()) - { - done_ = true; - } - } - - virtual bool ReadNextChunk(std::string& chunk) - { - if (done_) - { - return false; - } - else - { - chunk.swap(body_); - done_ = true; - return true; - } - } - }; - - - // This class mimics Orthanc::ChunkedBuffer - class ChunkedBuffer : public boost::noncopyable - { - private: - typedef std::list Content; - - Content content_; - size_t size_; - - public: - ChunkedBuffer() : - size_(0) - { - } - - ~ChunkedBuffer() - { - Clear(); - } - - void Clear() - { - for (Content::iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - - content_.clear(); - } - - void Flatten(std::string& target) const - { - target.resize(size_); - - size_t pos = 0; - - for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) - { - assert(*it != NULL); - size_t s = (*it)->size(); - - if (s != 0) - { - memcpy(&target[pos], (*it)->c_str(), s); - pos += s; - } - } - - assert(size_ == 0 || - pos == target.size()); - } - - void AddChunk(const void* data, - size_t size) - { - content_.push_back(new std::string(reinterpret_cast(data), size)); - size_ += size; - } - - void AddChunk(const std::string& chunk) - { - content_.push_back(new std::string(chunk)); - size_ += chunk.size(); - } - }; - - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - class MemoryAnswer : public HttpClient::IAnswer - { - private: - HttpClient::HttpHeaders headers_; - ChunkedBuffer body_; - - public: - const HttpClient::HttpHeaders& GetHeaders() const - { - return headers_; - } - - const ChunkedBuffer& GetBody() const - { - return body_; - } - - virtual void AddHeader(const std::string& key, - const std::string& value) - { - headers_[key] = value; - } - - virtual void AddChunk(const void* data, - size_t size) - { - body_.AddChunk(data, size); - } - }; -#endif - } - - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - void HttpClient::ExecuteWithStream(uint16_t& httpStatus, - IAnswer& answer, - IRequestBody& body) const - { - HeadersWrapper h(headers_); - - if (method_ == OrthancPluginHttpMethod_Post || - method_ == OrthancPluginHttpMethod_Put) - { - // Automatically set the "Transfer-Encoding" header if absent - bool found = false; - - for (HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); ++it) - { - if (boost::iequals(it->first, "Transfer-Encoding")) - { - found = true; - break; - } - } - - if (!found) - { - h.AddStaticString("Transfer-Encoding", "chunked"); - } - } - - RequestBodyWrapper request(body); - - OrthancPluginErrorCode error = OrthancPluginChunkedHttpClient( - GetGlobalContext(), - &answer, - AnswerAddChunkCallback, - AnswerAddHeaderCallback, - &httpStatus, - method_, - url_.c_str(), - h.GetCount(), - h.GetKeys(), - h.GetValues(), - &request, - RequestBodyWrapper::IsDone, - RequestBodyWrapper::GetChunkData, - RequestBodyWrapper::GetChunkSize, - RequestBodyWrapper::Next, - username_.empty() ? NULL : username_.c_str(), - password_.empty() ? NULL : password_.c_str(), - timeout_, - certificateFile_.empty() ? NULL : certificateFile_.c_str(), - certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(), - certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(), - pkcs11_ ? 1 : 0); - - if (error != OrthancPluginErrorCode_Success) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); - } - } -#endif - - - void HttpClient::ExecuteWithoutStream(uint16_t& httpStatus, - HttpHeaders& answerHeaders, - std::string& answerBody, - const std::string& body) const - { - HeadersWrapper headers(headers_); - - MemoryBuffer answerBodyBuffer, answerHeadersBuffer; - - OrthancPluginErrorCode error = OrthancPluginHttpClient( - GetGlobalContext(), - *answerBodyBuffer, - *answerHeadersBuffer, - &httpStatus, - method_, - url_.c_str(), - headers.GetCount(), - headers.GetKeys(), - headers.GetValues(), - body.empty() ? NULL : body.c_str(), - body.size(), - username_.empty() ? NULL : username_.c_str(), - password_.empty() ? NULL : password_.c_str(), - timeout_, - certificateFile_.empty() ? NULL : certificateFile_.c_str(), - certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(), - certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(), - pkcs11_ ? 1 : 0); - - if (error != OrthancPluginErrorCode_Success) - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); - } - - Json::Value v; - answerHeadersBuffer.ToJson(v); - - if (v.type() != Json::objectValue) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - Json::Value::Members members = v.getMemberNames(); - answerHeaders.clear(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& h = v[members[i]]; - if (h.type() != Json::stringValue) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - else - { - answerHeaders[members[i]] = h.asString(); - } - } - - answerBodyBuffer.ToString(answerBody); - } - - - void HttpClient::Execute(IAnswer& answer) - { -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - if (allowChunkedTransfers_) - { - if (chunkedBody_ != NULL) - { - ExecuteWithStream(httpStatus_, answer, *chunkedBody_); - } - else - { - MemoryRequestBody wrapper(fullBody_); - ExecuteWithStream(httpStatus_, answer, wrapper); - } - - return; - } -#endif - - // Compatibility mode for Orthanc SDK <= 1.5.6 or if chunked - // transfers are disabled. This results in higher memory usage - // (all chunks from the answer body are sent at once) - - HttpHeaders answerHeaders; - std::string answerBody; - Execute(answerHeaders, answerBody); - - for (HttpHeaders::const_iterator it = answerHeaders.begin(); - it != answerHeaders.end(); ++it) - { - answer.AddHeader(it->first, it->second); - } - - if (!answerBody.empty()) - { - answer.AddChunk(answerBody.c_str(), answerBody.size()); - } - } - - - void HttpClient::Execute(HttpHeaders& answerHeaders /* out */, - std::string& answerBody /* out */) - { -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - if (allowChunkedTransfers_) - { - MemoryAnswer answer; - Execute(answer); - answerHeaders = answer.GetHeaders(); - answer.GetBody().Flatten(answerBody); - return; - } -#endif - - // Compatibility mode for Orthanc SDK <= 1.5.6 or if chunked - // transfers are disabled. This results in higher memory usage - // (all chunks from the request body are sent at once) - - if (chunkedBody_ != NULL) - { - ChunkedBuffer buffer; - - std::string chunk; - while (chunkedBody_->ReadNextChunk(chunk)) - { - buffer.AddChunk(chunk); - } - - std::string body; - buffer.Flatten(body); - - ExecuteWithoutStream(httpStatus_, answerHeaders, answerBody, body); - } - else - { - ExecuteWithoutStream(httpStatus_, answerHeaders, answerBody, fullBody_); - } - } - - - void HttpClient::Execute(HttpHeaders& answerHeaders /* out */, - Json::Value& answerBody /* out */) - { - std::string body; - Execute(answerHeaders, body); - - Json::Reader reader; - if (!reader.parse(body, answerBody)) - { - LogError("Cannot convert HTTP answer body to JSON"); - ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); - } - } - - - void HttpClient::Execute() - { - HttpHeaders answerHeaders; - std::string body; - Execute(answerHeaders, body); - } - -#endif /* HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 */ - - - - - - /****************************************************************** - ** CHUNKED HTTP SERVER - ******************************************************************/ - - namespace Internals - { - void NullRestCallback(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request) - { - } - - IChunkedRequestReader *NullChunkedRestCallback(const char* url, - const OrthancPluginHttpRequest* request) - { - return NULL; - } - - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 - - OrthancPluginErrorCode ChunkedRequestReaderAddChunk( - OrthancPluginServerChunkedRequestReader* reader, - const void* data, - uint32_t size) - { - try - { - if (reader == NULL) - { - return OrthancPluginErrorCode_InternalError; - } - - reinterpret_cast(reader)->AddChunk(data, size); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (boost::bad_lexical_cast&) - { - return OrthancPluginErrorCode_BadFileFormat; - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } - - - OrthancPluginErrorCode ChunkedRequestReaderExecute( - OrthancPluginServerChunkedRequestReader* reader, - OrthancPluginRestOutput* output) - { - try - { - if (reader == NULL) - { - return OrthancPluginErrorCode_InternalError; - } - - reinterpret_cast(reader)->Execute(output); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (boost::bad_lexical_cast&) - { - return OrthancPluginErrorCode_BadFileFormat; - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } - - - void ChunkedRequestReaderFinalize( - OrthancPluginServerChunkedRequestReader* reader) - { - if (reader != NULL) - { - delete reinterpret_cast(reader); - } - } - -#else - - OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request, - RestCallback GetHandler, - ChunkedRestCallback PostHandler, - RestCallback DeleteHandler, - ChunkedRestCallback PutHandler) - { - try - { - std::string allowed; - - if (GetHandler != Internals::NullRestCallback) - { - allowed += "GET"; - } - - if (PostHandler != Internals::NullChunkedRestCallback) - { - if (!allowed.empty()) - { - allowed += ","; - } - - allowed += "POST"; - } - - if (DeleteHandler != Internals::NullRestCallback) - { - if (!allowed.empty()) - { - allowed += ","; - } - - allowed += "DELETE"; - } - - if (PutHandler != Internals::NullChunkedRestCallback) - { - if (!allowed.empty()) - { - allowed += ","; - } - - allowed += "PUT"; - } - - switch (request->method) - { - case OrthancPluginHttpMethod_Get: - if (GetHandler == Internals::NullRestCallback) - { - OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); - } - else - { - GetHandler(output, url, request); - } - - break; - - case OrthancPluginHttpMethod_Post: - if (PostHandler == Internals::NullChunkedRestCallback) - { - OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); - } - else - { - boost::movelib::unique_ptr reader(PostHandler(url, request)); - if (reader.get() == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); - } - else - { - reader->AddChunk(request->body, request->bodySize); - reader->Execute(output); - } - } - - break; - - case OrthancPluginHttpMethod_Delete: - if (DeleteHandler == Internals::NullRestCallback) - { - OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); - } - else - { - DeleteHandler(output, url, request); - } - - break; - - case OrthancPluginHttpMethod_Put: - if (PutHandler == Internals::NullChunkedRestCallback) - { - OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); - } - else - { - boost::movelib::unique_ptr reader(PutHandler(url, request)); - if (reader.get() == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); - } - else - { - reader->AddChunk(request->body, request->bodySize); - reader->Execute(output); - } - } - - break; - - default: - ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); - } - - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { -#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1 - if (HasGlobalContext() && - e.HasDetails()) - { - // The "false" instructs Orthanc not to log the detailed - // error message. This is to avoid duplicating the details, - // because "OrthancException" already does it on construction. - OrthancPluginSetHttpErrorDetails - (GetGlobalContext(), output, e.GetDetails(), false); - } -#endif - - return static_cast(e.GetErrorCode()); - } - catch (boost::bad_lexical_cast&) - { - return OrthancPluginErrorCode_BadFileFormat; - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } -#endif - } - - -#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1 - OrthancPluginErrorCode IStorageCommitmentScpHandler::Lookup( - OrthancPluginStorageCommitmentFailureReason* target, - void* rawHandler, - const char* sopClassUid, - const char* sopInstanceUid) - { - assert(target != NULL && - rawHandler != NULL); - - try - { - IStorageCommitmentScpHandler& handler = *reinterpret_cast(rawHandler); - *target = handler.Lookup(sopClassUid, sopInstanceUid); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } -#endif - - -#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1 - void IStorageCommitmentScpHandler::Destructor(void* rawHandler) - { - assert(rawHandler != NULL); - delete reinterpret_cast(rawHandler); - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - DicomInstance::DicomInstance(const OrthancPluginDicomInstance* instance) : - toFree_(false), - instance_(instance) - { - } -#else - DicomInstance::DicomInstance(OrthancPluginDicomInstance* instance) : - toFree_(false), - instance_(instance) - { - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - DicomInstance::DicomInstance(const void* buffer, - size_t size) : - toFree_(true), - instance_(OrthancPluginCreateDicomInstance(GetGlobalContext(), buffer, size)) - { - if (instance_ == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(NullPointer); - } - } -#endif - - - DicomInstance::~DicomInstance() - { -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - if (toFree_ && - instance_ != NULL) - { - OrthancPluginFreeDicomInstance( - GetGlobalContext(), const_cast(instance_)); - } -#endif - } - - - std::string DicomInstance::GetRemoteAet() const - { - const char* s = OrthancPluginGetInstanceRemoteAet(GetGlobalContext(), instance_); - if (s == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); - } - else - { - return std::string(s); - } - } - - - void DicomInstance::GetJson(Json::Value& target) const - { - OrthancString s; - s.Assign(OrthancPluginGetInstanceJson(GetGlobalContext(), instance_)); - s.ToJson(target); - } - - - void DicomInstance::GetSimplifiedJson(Json::Value& target) const - { - OrthancString s; - s.Assign(OrthancPluginGetInstanceSimplifiedJson(GetGlobalContext(), instance_)); - s.ToJson(target); - } - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - std::string DicomInstance::GetTransferSyntaxUid() const - { - OrthancString s; - s.Assign(OrthancPluginGetInstanceTransferSyntaxUid(GetGlobalContext(), instance_)); - - std::string result; - s.ToString(result); - return result; - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - bool DicomInstance::HasPixelData() const - { - int32_t result = OrthancPluginHasInstancePixelData(GetGlobalContext(), instance_); - if (result < 0) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); - } - else - { - return (result != 0); - } - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - void DicomInstance::GetRawFrame(std::string& target, - unsigned int frameIndex) const - { - MemoryBuffer buffer; - OrthancPluginErrorCode code = OrthancPluginGetInstanceRawFrame( - GetGlobalContext(), *buffer, instance_, frameIndex); - - if (code == OrthancPluginErrorCode_Success) - { - buffer.ToString(target); - } - else - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); - } - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - OrthancImage* DicomInstance::GetDecodedFrame(unsigned int frameIndex) const - { - OrthancPluginImage* image = OrthancPluginGetInstanceDecodedFrame( - GetGlobalContext(), instance_, frameIndex); - - if (image == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); - } - else - { - return new OrthancImage(image); - } - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - void DicomInstance::Serialize(std::string& target) const - { - MemoryBuffer buffer; - OrthancPluginErrorCode code = OrthancPluginSerializeDicomInstance( - GetGlobalContext(), *buffer, instance_); - - if (code == OrthancPluginErrorCode_Success) - { - buffer.ToString(target); - } - else - { - ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); - } - } -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - DicomInstance* DicomInstance::Transcode(const void* buffer, - size_t size, - const std::string& transferSyntax) - { - OrthancPluginDicomInstance* instance = OrthancPluginTranscodeDicomInstance( - GetGlobalContext(), buffer, size, transferSyntax.c_str()); - - if (instance == NULL) - { - ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); - } - else - { - boost::movelib::unique_ptr result(new DicomInstance(instance)); - result->toFree_ = true; - return result.release(); - } - } -#endif -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginCppWrapper.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1230 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#include "OrthancPluginException.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/** - * The definition of ORTHANC_PLUGINS_VERSION_IS_ABOVE below is for - * backward compatibility with Orthanc SDK <= 1.3.0. - * - * $ hg diff -r Orthanc-1.3.0:Orthanc-1.3.1 ../../../Plugins/Include/orthanc/OrthancCPlugin.h - * - **/ -#if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) -#define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \ - (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \ - (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \ - (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \ - (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \ - ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision)))) -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0) -// The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0 -# define HAS_ORTHANC_PLUGIN_FIND_MATCHER 1 -#else -# define HAS_ORTHANC_PLUGIN_FIND_MATCHER 0 -#endif - - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 4, 2) -# define HAS_ORTHANC_PLUGIN_PEERS 1 -# define HAS_ORTHANC_PLUGIN_JOB 1 -#else -# define HAS_ORTHANC_PLUGIN_PEERS 0 -# define HAS_ORTHANC_PLUGIN_JOB 0 -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) -# define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 1 -#else -# define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 0 -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) -# define HAS_ORTHANC_PLUGIN_METRICS 1 -#else -# define HAS_ORTHANC_PLUGIN_METRICS 0 -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 1, 0) -# define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 1 -#else -# define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 0 -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7) -# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 1 -#else -# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 0 -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7) -# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 1 -#else -# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 0 -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 0) -# define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 1 -#else -# define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 0 -#endif - - - -namespace OrthancPlugins -{ - typedef void (*RestCallback) (OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request); - - void SetGlobalContext(OrthancPluginContext* context); - - bool HasGlobalContext(); - - OrthancPluginContext* GetGlobalContext(); - - - class OrthancImage; - - - class MemoryBuffer : public boost::noncopyable - { - private: - OrthancPluginMemoryBuffer buffer_; - - void Check(OrthancPluginErrorCode code); - - bool CheckHttp(OrthancPluginErrorCode code); - - public: - MemoryBuffer(); - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - // This constructor makes a copy of the given buffer in the memory - // handled by the Orthanc core - MemoryBuffer(const void* buffer, - size_t size); -#endif - - ~MemoryBuffer() - { - Clear(); - } - - OrthancPluginMemoryBuffer* operator*() - { - return &buffer_; - } - - // This transfers ownership from "other" to "this" - void Assign(OrthancPluginMemoryBuffer& other); - - void Swap(MemoryBuffer& other); - - OrthancPluginMemoryBuffer Release(); - - const char* GetData() const - { - if (buffer_.size > 0) - { - return reinterpret_cast(buffer_.data); - } - else - { - return NULL; - } - } - - size_t GetSize() const - { - return buffer_.size; - } - - bool IsEmpty() const - { - return GetSize() == 0 || GetData() == NULL; - } - - void Clear(); - - void ToString(std::string& target) const; - - void ToJson(Json::Value& target) const; - - bool RestApiGet(const std::string& uri, - bool applyPlugins); - - bool RestApiGet(const std::string& uri, - const std::map& httpHeaders, - bool applyPlugins); - - bool RestApiPost(const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins); - - bool RestApiPut(const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins); - - bool RestApiPost(const std::string& uri, - const Json::Value& body, - bool applyPlugins); - - bool RestApiPut(const std::string& uri, - const Json::Value& body, - bool applyPlugins); - - bool RestApiPost(const std::string& uri, - const std::string& body, - bool applyPlugins) - { - return RestApiPost(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins); - } - - bool RestApiPut(const std::string& uri, - const std::string& body, - bool applyPlugins) - { - return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins); - } - - void CreateDicom(const Json::Value& tags, - OrthancPluginCreateDicomFlags flags); - - void CreateDicom(const Json::Value& tags, - const OrthancImage& pixelData, - OrthancPluginCreateDicomFlags flags); - - void ReadFile(const std::string& path); - - void GetDicomQuery(const OrthancPluginWorklistQuery* query); - - void DicomToJson(Json::Value& target, - OrthancPluginDicomToJsonFormat format, - OrthancPluginDicomToJsonFlags flags, - uint32_t maxStringLength); - - bool HttpGet(const std::string& url, - const std::string& username, - const std::string& password); - - bool HttpPost(const std::string& url, - const std::string& body, - const std::string& username, - const std::string& password); - - bool HttpPut(const std::string& url, - const std::string& body, - const std::string& username, - const std::string& password); - - void GetDicomInstance(const std::string& instanceId); - }; - - - class OrthancString : public boost::noncopyable - { - private: - char* str_; - - void Clear(); - - public: - OrthancString() : - str_(NULL) - { - } - - ~OrthancString() - { - Clear(); - } - - // This transfers ownership, warning: The string must have been - // allocated by the Orthanc core - void Assign(char* str); - - const char* GetContent() const - { - return str_; - } - - void ToString(std::string& target) const; - - void ToJson(Json::Value& target) const; - }; - - - class OrthancConfiguration : public boost::noncopyable - { - private: - Json::Value configuration_; // Necessarily a Json::objectValue - std::string path_; - - std::string GetPath(const std::string& key) const; - - void LoadConfiguration(); - - public: - OrthancConfiguration(); - - explicit OrthancConfiguration(bool load); - - const Json::Value& GetJson() const - { - return configuration_; - } - - bool IsSection(const std::string& key) const; - - void GetSection(OrthancConfiguration& target, - const std::string& key) const; - - bool LookupStringValue(std::string& target, - const std::string& key) const; - - bool LookupIntegerValue(int& target, - const std::string& key) const; - - bool LookupUnsignedIntegerValue(unsigned int& target, - const std::string& key) const; - - bool LookupBooleanValue(bool& target, - const std::string& key) const; - - bool LookupFloatValue(float& target, - const std::string& key) const; - - bool LookupListOfStrings(std::list& target, - const std::string& key, - bool allowSingleString) const; - - bool LookupSetOfStrings(std::set& target, - const std::string& key, - bool allowSingleString) const; - - std::string GetStringValue(const std::string& key, - const std::string& defaultValue) const; - - int GetIntegerValue(const std::string& key, - int defaultValue) const; - - unsigned int GetUnsignedIntegerValue(const std::string& key, - unsigned int defaultValue) const; - - bool GetBooleanValue(const std::string& key, - bool defaultValue) const; - - float GetFloatValue(const std::string& key, - float defaultValue) const; - - void GetDictionary(std::map& target, - const std::string& key) const; - }; - - class OrthancImage : public boost::noncopyable - { - private: - OrthancPluginImage* image_; - - void Clear(); - - void CheckImageAvailable() const; - - public: - OrthancImage(); - - explicit OrthancImage(OrthancPluginImage* image); - - OrthancImage(OrthancPluginPixelFormat format, - uint32_t width, - uint32_t height); - - OrthancImage(OrthancPluginPixelFormat format, - uint32_t width, - uint32_t height, - uint32_t pitch, - void* buffer); - - ~OrthancImage() - { - Clear(); - } - - void UncompressPngImage(const void* data, - size_t size); - - void UncompressJpegImage(const void* data, - size_t size); - - void DecodeDicomImage(const void* data, - size_t size, - unsigned int frame); - - OrthancPluginPixelFormat GetPixelFormat() const; - - unsigned int GetWidth() const; - - unsigned int GetHeight() const; - - unsigned int GetPitch() const; - - void* GetBuffer() const; - - const OrthancPluginImage* GetObject() const - { - return image_; - } - - void CompressPngImage(MemoryBuffer& target) const; - - void CompressJpegImage(MemoryBuffer& target, - uint8_t quality) const; - - void AnswerPngImage(OrthancPluginRestOutput* output) const; - - void AnswerJpegImage(OrthancPluginRestOutput* output, - uint8_t quality) const; - - void* GetWriteableBuffer(); - - OrthancPluginImage* Release(); - }; - - -#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 - class FindMatcher : public boost::noncopyable - { - private: - OrthancPluginFindMatcher* matcher_; - const OrthancPluginWorklistQuery* worklist_; - - void SetupDicom(const void* query, - uint32_t size); - - public: - explicit FindMatcher(const OrthancPluginWorklistQuery* worklist); - - FindMatcher(const void* query, - uint32_t size) - { - SetupDicom(query, size); - } - - explicit FindMatcher(const MemoryBuffer& dicom) - { - SetupDicom(dicom.GetData(), dicom.GetSize()); - } - - ~FindMatcher(); - - bool IsMatch(const void* dicom, - uint32_t size) const; - - bool IsMatch(const MemoryBuffer& dicom) const - { - return IsMatch(dicom.GetData(), dicom.GetSize()); - } - }; -#endif - - - bool RestApiGet(Json::Value& result, - const std::string& uri, - bool applyPlugins); - - bool RestApiGetString(std::string& result, - const std::string& uri, - bool applyPlugins); - - bool RestApiGetString(std::string& result, - const std::string& uri, - const std::map& httpHeaders, - bool applyPlugins); - - bool RestApiPost(std::string& result, - const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins); - - bool RestApiPost(Json::Value& result, - const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins); - - bool RestApiPost(Json::Value& result, - const std::string& uri, - const Json::Value& body, - bool applyPlugins); - - inline bool RestApiPost(Json::Value& result, - const std::string& uri, - const std::string& body, - bool applyPlugins) - { - return RestApiPost(result, uri, body.empty() ? NULL : body.c_str(), - body.size(), applyPlugins); - } - - inline bool RestApiPost(Json::Value& result, - const std::string& uri, - const MemoryBuffer& body, - bool applyPlugins) - { - return RestApiPost(result, uri, body.GetData(), - body.GetSize(), applyPlugins); - } - - bool RestApiPut(Json::Value& result, - const std::string& uri, - const void* body, - size_t bodySize, - bool applyPlugins); - - bool RestApiPut(Json::Value& result, - const std::string& uri, - const Json::Value& body, - bool applyPlugins); - - inline bool RestApiPut(Json::Value& result, - const std::string& uri, - const std::string& body, - bool applyPlugins) - { - return RestApiPut(result, uri, body.empty() ? NULL : body.c_str(), - body.size(), applyPlugins); - } - - bool RestApiDelete(const std::string& uri, - bool applyPlugins); - - bool HttpDelete(const std::string& url, - const std::string& username, - const std::string& password); - - void AnswerJson(const Json::Value& value, - OrthancPluginRestOutput* output); - - void AnswerString(const std::string& answer, - const char* mimeType, - OrthancPluginRestOutput* output); - - void AnswerHttpError(uint16_t httpError, - OrthancPluginRestOutput* output); - - void AnswerMethodNotAllowed(OrthancPluginRestOutput* output, const char* allowedMethods); - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) - const char* AutodetectMimeType(const std::string& path); -#endif - - void LogError(const std::string& message); - - void LogWarning(const std::string& message); - - void LogInfo(const std::string& message); - - void ReportMinimalOrthancVersion(unsigned int major, - unsigned int minor, - unsigned int revision); - - bool CheckMinimalOrthancVersion(unsigned int major, - unsigned int minor, - unsigned int revision); - - - namespace Internals - { - template - static OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request) - { - try - { - Callback(output, url, request); - return OrthancPluginErrorCode_Success; - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { -#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1 - if (HasGlobalContext() && - e.HasDetails()) - { - // The "false" instructs Orthanc not to log the detailed - // error message. This is to avoid duplicating the details, - // because "OrthancException" already does it on construction. - OrthancPluginSetHttpErrorDetails - (GetGlobalContext(), output, e.GetDetails(), false); - } -#endif - - return static_cast(e.GetErrorCode()); - } - catch (boost::bad_lexical_cast&) - { - return OrthancPluginErrorCode_BadFileFormat; - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } - } - - - template - void RegisterRestCallback(const std::string& uri, - bool isThreadSafe) - { - if (isThreadSafe) - { - OrthancPluginRegisterRestCallbackNoLock - (GetGlobalContext(), uri.c_str(), Internals::Protect); - } - else - { - OrthancPluginRegisterRestCallback - (GetGlobalContext(), uri.c_str(), Internals::Protect); - } - } - - -#if HAS_ORTHANC_PLUGIN_PEERS == 1 - class OrthancPeers : public boost::noncopyable - { - private: - typedef std::map Index; - - OrthancPluginPeers *peers_; - Index index_; - uint32_t timeout_; - - size_t GetPeerIndex(const std::string& name) const; - - public: - OrthancPeers(); - - ~OrthancPeers(); - - uint32_t GetTimeout() const - { - return timeout_; - } - - void SetTimeout(uint32_t timeout) - { - timeout_ = timeout; - } - - bool LookupName(size_t& target, - const std::string& name) const; - - std::string GetPeerName(size_t index) const; - - std::string GetPeerUrl(size_t index) const; - - std::string GetPeerUrl(const std::string& name) const; - - size_t GetPeersCount() const - { - return index_.size(); - } - - bool LookupUserProperty(std::string& value, - size_t index, - const std::string& key) const; - - bool LookupUserProperty(std::string& value, - const std::string& peer, - const std::string& key) const; - - bool DoGet(MemoryBuffer& target, - size_t index, - const std::string& uri) const; - - bool DoGet(MemoryBuffer& target, - const std::string& name, - const std::string& uri) const; - - bool DoGet(Json::Value& target, - size_t index, - const std::string& uri) const; - - bool DoGet(Json::Value& target, - const std::string& name, - const std::string& uri) const; - - bool DoPost(MemoryBuffer& target, - size_t index, - const std::string& uri, - const std::string& body) const; - - bool DoPost(MemoryBuffer& target, - const std::string& name, - const std::string& uri, - const std::string& body) const; - - bool DoPost(Json::Value& target, - size_t index, - const std::string& uri, - const std::string& body) const; - - bool DoPost(Json::Value& target, - const std::string& name, - const std::string& uri, - const std::string& body) const; - - bool DoPut(size_t index, - const std::string& uri, - const std::string& body) const; - - bool DoPut(const std::string& name, - const std::string& uri, - const std::string& body) const; - - bool DoDelete(size_t index, - const std::string& uri) const; - - bool DoDelete(const std::string& name, - const std::string& uri) const; - }; -#endif - - - -#if HAS_ORTHANC_PLUGIN_JOB == 1 - class OrthancJob : public boost::noncopyable - { - private: - std::string jobType_; - std::string content_; - bool hasSerialized_; - std::string serialized_; - float progress_; - - static void CallbackFinalize(void* job); - - static float CallbackGetProgress(void* job); - - static const char* CallbackGetContent(void* job); - - static const char* CallbackGetSerialized(void* job); - - static OrthancPluginJobStepStatus CallbackStep(void* job); - - static OrthancPluginErrorCode CallbackStop(void* job, - OrthancPluginJobStopReason reason); - - static OrthancPluginErrorCode CallbackReset(void* job); - - protected: - void ClearContent(); - - void UpdateContent(const Json::Value& content); - - void ClearSerialized(); - - void UpdateSerialized(const Json::Value& serialized); - - void UpdateProgress(float progress); - - public: - OrthancJob(const std::string& jobType); - - virtual ~OrthancJob() - { - } - - virtual OrthancPluginJobStepStatus Step() = 0; - - virtual void Stop(OrthancPluginJobStopReason reason) = 0; - - virtual void Reset() = 0; - - static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */); - - static std::string Submit(OrthancJob* job /* takes ownership */, - int priority); - - static void SubmitAndWait(Json::Value& result, - OrthancJob* job /* takes ownership */, - int priority); - - // Submit a job from a POST on the REST API with the same - // conventions as in the Orthanc core (according to the - // "Synchronous" and "Priority" options) - static void SubmitFromRestApiPost(OrthancPluginRestOutput* output, - const Json::Value& body, - OrthancJob* job); - }; -#endif - - -#if HAS_ORTHANC_PLUGIN_METRICS == 1 - inline void SetMetricsValue(char* name, - float value) - { - OrthancPluginSetMetricsValue(GetGlobalContext(), name, - value, OrthancPluginMetricsType_Default); - } - - class MetricsTimer : public boost::noncopyable - { - private: - std::string name_; - boost::posix_time::ptime start_; - - public: - explicit MetricsTimer(const char* name); - - ~MetricsTimer(); - }; -#endif - - -#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 - class HttpClient : public boost::noncopyable - { - public: - typedef std::map HttpHeaders; - - class IRequestBody : public boost::noncopyable - { - public: - virtual ~IRequestBody() - { - } - - virtual bool ReadNextChunk(std::string& chunk) = 0; - }; - - - class IAnswer : public boost::noncopyable - { - public: - virtual ~IAnswer() - { - } - - virtual void AddHeader(const std::string& key, - const std::string& value) = 0; - - virtual void AddChunk(const void* data, - size_t size) = 0; - }; - - - private: - class RequestBodyWrapper; - - uint16_t httpStatus_; - OrthancPluginHttpMethod method_; - std::string url_; - HttpHeaders headers_; - std::string username_; - std::string password_; - uint32_t timeout_; - std::string certificateFile_; - std::string certificateKeyFile_; - std::string certificateKeyPassword_; - bool pkcs11_; - std::string fullBody_; - IRequestBody* chunkedBody_; - bool allowChunkedTransfers_; - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 - void ExecuteWithStream(uint16_t& httpStatus, // out - IAnswer& answer, // out - IRequestBody& body) const; -#endif - - void ExecuteWithoutStream(uint16_t& httpStatus, // out - HttpHeaders& answerHeaders, // out - std::string& answerBody, // out - const std::string& body) const; - - public: - HttpClient(); - - uint16_t GetHttpStatus() const - { - return httpStatus_; - } - - void SetMethod(OrthancPluginHttpMethod method) - { - method_ = method; - } - - const std::string& GetUrl() const - { - return url_; - } - - void SetUrl(const std::string& url) - { - url_ = url; - } - - void SetHeaders(const HttpHeaders& headers) - { - headers_ = headers; - } - - void AddHeader(const std::string& key, - const std::string& value) - { - headers_[key] = value; - } - - void AddHeaders(const HttpHeaders& headers); - - void SetCredentials(const std::string& username, - const std::string& password); - - void ClearCredentials(); - - void SetTimeout(unsigned int timeout) // 0 for default timeout - { - timeout_ = timeout; - } - - void SetCertificate(const std::string& certificateFile, - const std::string& keyFile, - const std::string& keyPassword); - - void ClearCertificate(); - - void SetPkcs11(bool pkcs11) - { - pkcs11_ = pkcs11; - } - - void ClearBody(); - - void SwapBody(std::string& body); - - void SetBody(const std::string& body); - - void SetBody(IRequestBody& body); - - // This function can be used to disable chunked transfers if the - // remote server is Orthanc with a version <= 1.5.6. - void SetChunkedTransfersAllowed(bool allow) - { - allowChunkedTransfers_ = allow; - } - - bool IsChunkedTransfersAllowed() const - { - return allowChunkedTransfers_; - } - - void Execute(IAnswer& answer); - - void Execute(HttpHeaders& answerHeaders /* out */, - std::string& answerBody /* out */); - - void Execute(HttpHeaders& answerHeaders /* out */, - Json::Value& answerBody /* out */); - - void Execute(); - }; -#endif - - - - class IChunkedRequestReader : public boost::noncopyable - { - public: - virtual ~IChunkedRequestReader() - { - } - - virtual void AddChunk(const void* data, - size_t size) = 0; - - virtual void Execute(OrthancPluginRestOutput* output) = 0; - }; - - - typedef IChunkedRequestReader* (*ChunkedRestCallback) (const char* url, - const OrthancPluginHttpRequest* request); - - - namespace Internals - { - void NullRestCallback(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request); - - IChunkedRequestReader *NullChunkedRestCallback(const char* url, - const OrthancPluginHttpRequest* request); - - -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 - template - static OrthancPluginErrorCode ChunkedProtect(OrthancPluginServerChunkedRequestReader** reader, - const char* url, - const OrthancPluginHttpRequest* request) - { - try - { - if (reader == NULL) - { - return OrthancPluginErrorCode_InternalError; - } - else - { - *reader = reinterpret_cast(Callback(url, request)); - if (*reader == NULL) - { - return OrthancPluginErrorCode_Plugin; - } - else - { - return OrthancPluginErrorCode_Success; - } - } - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - return static_cast(e.GetErrorCode()); - } - catch (boost::bad_lexical_cast&) - { - return OrthancPluginErrorCode_BadFileFormat; - } - catch (...) - { - return OrthancPluginErrorCode_Plugin; - } - } - - OrthancPluginErrorCode ChunkedRequestReaderAddChunk( - OrthancPluginServerChunkedRequestReader* reader, - const void* data, - uint32_t size); - - OrthancPluginErrorCode ChunkedRequestReaderExecute( - OrthancPluginServerChunkedRequestReader* reader, - OrthancPluginRestOutput* output); - - void ChunkedRequestReaderFinalize( - OrthancPluginServerChunkedRequestReader* reader); - -#else - - OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request, - RestCallback GetHandler, - ChunkedRestCallback PostHandler, - RestCallback DeleteHandler, - ChunkedRestCallback PutHandler); - - template< - RestCallback GetHandler, - ChunkedRestCallback PostHandler, - RestCallback DeleteHandler, - ChunkedRestCallback PutHandler - > - inline OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output, - const char* url, - const OrthancPluginHttpRequest* request) - { - return ChunkedRestCompatibility(output, url, request, GetHandler, - PostHandler, DeleteHandler, PutHandler); - } -#endif - } - - - - // NB: We use a templated class instead of a templated function, because - // default values are only available in functions since C++11 - template< - RestCallback GetHandler = Internals::NullRestCallback, - ChunkedRestCallback PostHandler = Internals::NullChunkedRestCallback, - RestCallback DeleteHandler = Internals::NullRestCallback, - ChunkedRestCallback PutHandler = Internals::NullChunkedRestCallback - > - class ChunkedRestRegistration : public boost::noncopyable - { - public: - static void Apply(const std::string& uri) - { -#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 - OrthancPluginRegisterChunkedRestCallback( - GetGlobalContext(), uri.c_str(), - GetHandler == Internals::NullRestCallback ? NULL : Internals::Protect, - PostHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect, - DeleteHandler == Internals::NullRestCallback ? NULL : Internals::Protect, - PutHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect, - Internals::ChunkedRequestReaderAddChunk, - Internals::ChunkedRequestReaderExecute, - Internals::ChunkedRequestReaderFinalize); -#else - OrthancPluginRegisterRestCallbackNoLock( - GetGlobalContext(), uri.c_str(), - Internals::ChunkedRestCompatibility); -#endif - } - }; - - - -#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1 - class IStorageCommitmentScpHandler : public boost::noncopyable - { - public: - virtual ~IStorageCommitmentScpHandler() - { - } - - virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid, - const std::string& sopInstanceUid) = 0; - - static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target, - void* rawHandler, - const char* sopClassUid, - const char* sopInstanceUid); - - static void Destructor(void* rawHandler); - }; -#endif - - - class DicomInstance : public boost::noncopyable - { - private: - bool toFree_; - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - const OrthancPluginDicomInstance* instance_; -#else - OrthancPluginDicomInstance* instance_; -#endif - - public: -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - DicomInstance(const OrthancPluginDicomInstance* instance); -#else - DicomInstance(OrthancPluginDicomInstance* instance); -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - DicomInstance(const void* buffer, - size_t size); -#endif - - ~DicomInstance(); - - std::string GetRemoteAet() const; - - const void* GetBuffer() const - { - return OrthancPluginGetInstanceData(GetGlobalContext(), instance_); - } - - size_t GetSize() const - { - return static_cast(OrthancPluginGetInstanceSize(GetGlobalContext(), instance_)); - } - - void GetJson(Json::Value& target) const; - - void GetSimplifiedJson(Json::Value& target) const; - - OrthancPluginInstanceOrigin GetOrigin() const - { - return OrthancPluginGetInstanceOrigin(GetGlobalContext(), instance_); - } - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - std::string GetTransferSyntaxUid() const; -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) - bool HasPixelData() const; -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - unsigned int GetFramesCount() const - { - return OrthancPluginGetInstanceFramesCount(GetGlobalContext(), instance_); - } -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - void GetRawFrame(std::string& target, - unsigned int frameIndex) const; -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - OrthancImage* GetDecodedFrame(unsigned int frameIndex) const; -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - void Serialize(std::string& target) const; -#endif - -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) - static DicomInstance* Transcode(const void* buffer, - size_t size, - const std::string& transferSyntax); -#endif - }; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginException.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginException.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginException.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/OrthancPluginException.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(HAS_ORTHANC_EXCEPTION) -# error The macro HAS_ORTHANC_EXCEPTION must be defined -#endif - - -#if HAS_ORTHANC_EXCEPTION == 1 -# include "../../../Core/OrthancException.h" -# define ORTHANC_PLUGINS_ERROR_ENUMERATION ::Orthanc::ErrorCode -# define ORTHANC_PLUGINS_EXCEPTION_CLASS ::Orthanc::OrthancException -# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::Orthanc::ErrorCode_ ## code -#else -# include -# define ORTHANC_PLUGINS_ERROR_ENUMERATION ::OrthancPluginErrorCode -# define ORTHANC_PLUGINS_EXCEPTION_CLASS ::OrthancPlugins::PluginException -# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::OrthancPluginErrorCode_ ## code -#endif - - -#define ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code) \ - throw ORTHANC_PLUGINS_EXCEPTION_CLASS(static_cast(code)); - - -#define ORTHANC_PLUGINS_THROW_EXCEPTION(code) \ - throw ORTHANC_PLUGINS_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code)); - - -#define ORTHANC_PLUGINS_CHECK_ERROR(code) \ - if (code != ORTHANC_PLUGINS_GET_ERROR_CODE(Success)) \ - { \ - ORTHANC_PLUGINS_THROW_EXCEPTION(code); \ - } - - -namespace OrthancPlugins -{ -#if HAS_ORTHANC_EXCEPTION == 0 - class PluginException - { - private: - OrthancPluginErrorCode code_; - - public: - explicit PluginException(OrthancPluginErrorCode code) : code_(code) - { - } - - OrthancPluginErrorCode GetErrorCode() const - { - return code_; - } - - const char* What(OrthancPluginContext* context) const - { - const char* description = OrthancPluginGetErrorDescription(context, code_); - if (description) - { - return description; - } - else - { - return "No description available"; - } - } - }; -#endif -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/VersionScript.map orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/VersionScript.map --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/VersionScript.map 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Plugins/Samples/Common/VersionScript.map 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -# This is a version-script for Orthanc plugins - -{ -global: - OrthancPluginInitialize; - OrthancPluginFinalize; - OrthancPluginGetName; - OrthancPluginGetVersion; - -local: - *; -}; diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/README orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/README --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/README 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,102 +0,0 @@ -Orthanc - A Lightweight, RESTful DICOM Server -============================================= - - -General Information -------------------- - -General information about this software can be found on its official -Website: -http://www.orthanc-server.com/ - -The instructions for building Orthanc can be found in the "INSTALL" -file. - - -Supported Platforms -------------------- - -Currently, the officially validated platforms are: - -* GNU/Linux (32bit and 64bit). -* Windows (32bit and 64bit). -* Apple OS X (32bit and 64bit). - -Orthanc is known to work on other UNIX-like platforms (such as FreeBSD -and OpenBSD). - - -Supported Toolchains --------------------- - -Orthanc can currently be built using the following compiling -toolchains: - -* Native GNU/Linux compilation, with gcc. -* Native Windows compilation, with Microsoft Visual Studio. -* Cross-compilation for Windows under GNU/Linux, with MinGW. - - -Licensing ---------- - -Orthanc is licensed under the GPLv3 license, with the OpenSSL -exception: -http://people.gnome.org/~markmc/openssl-and-the-gpl.html - -We also kindly ask scientific works and clinical studies that make -use of Orthanc to cite Orthanc in their associated publications. -Similarly, we ask open-source and closed-source products that make -use of Orthanc to warn us about this use. You can cite our work -using the following BibTeX entry: - -@Article{Jodogne2018, - author="Jodogne, S{\'e}bastien", - title="The {O}rthanc Ecosystem for Medical Imaging", - journal="Journal of Digital Imaging", - year="2018", - month="Jun", - day="01", - volume="31", - number="3", - pages="341--352", - issn="1618-727X", - doi="10.1007/s10278-018-0082-y", - url="https://doi.org/10.1007/s10278-018-0082-y" -} - - -Licensing of special directories --------------------------------- - -The following directories have separate licensing terms: - -* The file of the "Core/SQLite/" directory are licensed under the - 3-clause BSD license, as they are derived from the Chromium project. - - -Content -------- - -This archive contains the following directories: - -* Core/ - The core C++ classes (independent of DCMTK) -* OrthancExplorer/ - Code of the Web application (HTML5/Javascript) -* OrthancServer/ - Code of the Orthanc server (depends on DCMTK) -* Plugins/ - Code of the plugin framework -* Resources/ - Scripts, resources for building third-party code -* UnitTestsSources/ - Unit tests - -This archive contains the following files: - -* AUTHORS - The list of the authors -* CMakeLists.txt - The main build script -* COPYING - The GPLv3 license -* INSTALL - How to build Orthanc -* README - This file -* THANKS - The list of the contributors -* NEWS - The history of main changes between versions - -We have decided not to maintain a separate "ChangeLog" file. Each -commit to the official Orthanc Mercurial repository should be -associated with a description of the changes. diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/AutoGeneratedCode.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/AutoGeneratedCode.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/AutoGeneratedCode.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/AutoGeneratedCode.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED") -set(AUTOGENERATED_SOURCES) - -file(MAKE_DIRECTORY ${AUTOGENERATED_DIR}) -include_directories(${AUTOGENERATED_DIR}) - -macro(EmbedResources) - # Convert a semicolon separated list to a whitespace separated string - set(SCRIPT_OPTIONS) - set(SCRIPT_ARGUMENTS) - set(DEPENDENCIES) - set(IS_PATH_NAME false) - - # Loop over the arguments of the function - foreach(arg ${ARGN}) - # Extract the first character of the argument - string(SUBSTRING "${arg}" 0 1 FIRST_CHAR) - if (${FIRST_CHAR} STREQUAL "-") - # If the argument starts with a dash "-", this is an option to - # EmbedResources.py - list(APPEND SCRIPT_OPTIONS ${arg}) - else() - if (${IS_PATH_NAME}) - list(APPEND SCRIPT_ARGUMENTS "${arg}") - list(APPEND DEPENDENCIES "${arg}") - set(IS_PATH_NAME false) - else() - list(APPEND SCRIPT_ARGUMENTS "${arg}") - set(IS_PATH_NAME true) - endif() - endif() - endforeach() - - set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources") - add_custom_command( - OUTPUT - "${TARGET_BASE}.h" - "${TARGET_BASE}.cpp" - COMMAND - ${PYTHON_EXECUTABLE} - "${ORTHANC_ROOT}/Resources/EmbedResources.py" - ${SCRIPT_OPTIONS} - "${AUTOGENERATED_DIR}/EmbeddedResources" - ${SCRIPT_ARGUMENTS} - DEPENDS - "${ORTHANC_ROOT}/Resources/EmbedResources.py" - ${DEPENDENCIES} - ) - - list(APPEND AUTOGENERATED_SOURCES - "${AUTOGENERATED_DIR}/EmbeddedResources.cpp" - ) -endmacro() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,383 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_BOOST) - set(BOOST_STATIC 1) -else() - include(FindBoost) - - set(BOOST_STATIC 0) - #set(Boost_DEBUG 1) - #set(Boost_USE_STATIC_LIBS ON) - - if (ENABLE_LOCALE) - list(APPEND ORTHANC_BOOST_COMPONENTS locale) - endif() - - list(APPEND ORTHANC_BOOST_COMPONENTS filesystem thread system date_time regex) - find_package(Boost COMPONENTS ${ORTHANC_BOOST_COMPONENTS}) - - if (NOT Boost_FOUND) - foreach (item ${ORTHANC_BOOST_COMPONENTS}) - string(TOUPPER ${item} tmp) - - if (Boost_${tmp}_FOUND) - set(tmp2 "found") - else() - set(tmp2 "missing") - endif() - - message("Boost component ${item} - ${tmp2}") - endforeach() - - message(FATAL_ERROR "Unable to locate Boost on this system") - endif() - - - # Patch by xnox to fix issue #166 (CMake find_boost version is now - # broken with newer boost/cmake) - # https://bitbucket.org/sjodogne/orthanc/issues/166/ - if (POLICY CMP0093) - set(BOOST144 1.44) - else() - set(BOOST144 104400) - endif() - - - # Boost releases 1.44 through 1.47 supply both V2 and V3 filesystem - # http://www.boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/index.htm - if (${Boost_VERSION} LESS ${BOOST144}) - add_definitions( - -DBOOST_HAS_FILESYSTEM_V3=0 - ) - else() - add_definitions( - -DBOOST_HAS_FILESYSTEM_V3=1 - -DBOOST_FILESYSTEM_VERSION=3 - ) - endif() - - include_directories(${Boost_INCLUDE_DIRS}) - link_libraries(${Boost_LIBRARIES}) -endif() - - -if (BOOST_STATIC) - ## - ## Parameters for static compilation of Boost - ## - - set(BOOST_NAME boost_1_69_0) - set(BOOST_VERSION 1.69.0) - set(BOOST_BCP_SUFFIX bcpdigest-1.5.6) - set(BOOST_MD5 "579bccc0ea4d1a261c1d0c5e27446c3d") - set(BOOST_URL "http://orthanc.osimis.io/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") - set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) - - if (IS_DIRECTORY "${BOOST_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() - - DownloadPackage(${BOOST_MD5} ${BOOST_URL} "${BOOST_SOURCES_DIR}") - - - ## - ## Patching boost - ## - - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/boost-${BOOST_VERSION}-linux-standard-base.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (FirstRun AND Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - - ## - ## Generic configuration of Boost - ## - - if (CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-isystem ${BOOST_SOURCES_DIR}) - endif() - - include_directories( - BEFORE ${BOOST_SOURCES_DIR} - ) - - add_definitions( - # Static build of Boost - -DBOOST_ALL_NO_LIB - -DBOOST_ALL_NOLIB - -DBOOST_DATE_TIME_NO_LIB - -DBOOST_THREAD_BUILD_LIB - -DBOOST_PROGRAM_OPTIONS_NO_LIB - -DBOOST_REGEX_NO_LIB - -DBOOST_SYSTEM_NO_LIB - -DBOOST_LOCALE_NO_LIB - - # In static builds, explicitly prevent Boost from using the system - # locale in lexical casts. This is notably important if - # "boost::lexical_cast()" is applied to strings containing - # "," instead of "." as decimal separators. Check out function - # "OrthancStone::LinearAlgebra::ParseVector()". - -DBOOST_LEXICAL_CAST_ASSUME_C_LOCALE - ) - - set(BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp - ) - - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase" OR - "${CMAKE_SYSTEM_NAME}" STREQUAL "Android") - add_definitions( - -DBOOST_SYSTEM_USE_STRERROR=1 - ) - endif() - - - ## - ## Configuration of boost::thread - ## - - if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR - CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR - CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl64" OR - CMAKE_SYSTEM_NAME STREQUAL "Android") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/atomic/src/lockpool.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/pthread/thread.cpp - ) - - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase" OR - CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl64") - add_definitions(-DBOOST_HAS_SCHED_YIELD=1) - endif() - - # Fix for error: "boost_1_69_0/boost/chrono/detail/inlined/mac/thread_clock.hpp:54:28: - # error: use of undeclared identifier 'pthread_mach_thread_np'" - # https://github.com/envoyproxy/envoy/pull/1785 - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") - add_definitions(-D_DARWIN_C_SOURCE=1) - endif() - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_dll.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/win32/thread.cpp - ${BOOST_SOURCES_DIR}/libs/thread/src/win32/tss_pe.cpp - ) - - elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - # No support for threads in asm.js/WebAssembly - - else() - message(FATAL_ERROR "Support your platform here") - endif() - - - ## - ## Configuration of boost::regex - ## - - aux_source_directory(${BOOST_SOURCES_DIR}/libs/regex/src BOOST_REGEX_SOURCES) - - list(APPEND BOOST_SOURCES - ${BOOST_REGEX_SOURCES} - ) - - - ## - ## Configuration of boost::datetime - ## - - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/date_time/src/gregorian/greg_month.cpp - ) - - - ## - ## Configuration of boost::filesystem - ## - - if (CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl64" OR - CMAKE_SYSTEM_NAME STREQUAL "Android") - # boost::filesystem is not available on PNaCl - add_definitions( - -DBOOST_HAS_FILESYSTEM_V3=0 - -D__INTEGRITY=1 - ) - else() - add_definitions( - -DBOOST_HAS_FILESYSTEM_V3=1 - ) - list(APPEND BOOST_SOURCES - ${BOOST_NAME}/libs/filesystem/src/codecvt_error_category.cpp - ${BOOST_NAME}/libs/filesystem/src/operations.cpp - ${BOOST_NAME}/libs/filesystem/src/path.cpp - ${BOOST_NAME}/libs/filesystem/src/path_traits.cpp - ) - - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR - CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/filesystem/src/utf8_codecvt_facet.cpp - ) - - elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") - list(APPEND BOOST_SOURCES - ${BOOST_NAME}/libs/filesystem/src/windows_file_codecvt.cpp - ) - endif() - endif() - - - ## - ## Configuration of boost::locale - ## - - if (NOT ENABLE_LOCALE) - message("boost::locale is disabled") - else() - set(BOOST_ICU_SOURCES - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/boundary.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/codecvt.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/collator.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/conversion.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/date_time.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/formatter.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/icu_backend.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/numeric.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/icu/time_zone.cpp - ) - - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/generator.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/date_time.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/formatting.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/ids.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/localization_backend.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/message.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/shared/mo_lambda.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/util/codecvt_converter.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/util/default_locale.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/util/gregorian.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/util/info.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/util/locale_data.cpp - ) - - if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR - CMAKE_SYSTEM_VERSION STREQUAL "LinuxStandardBase") - add_definitions( - -DBOOST_LOCALE_NO_WINAPI_BACKEND=1 - -DBOOST_LOCALE_NO_POSIX_BACKEND=1 - ) - - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/locale/src/std/codecvt.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/collate.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/converter.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/numeric.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/std_backend.cpp - ) - - if (BOOST_LOCALE_BACKEND STREQUAL "gcc" OR - BOOST_LOCALE_BACKEND STREQUAL "libiconv") - add_definitions(-DBOOST_LOCALE_WITH_ICONV=1) - elseif (BOOST_LOCALE_BACKEND STREQUAL "icu") - add_definitions(-DBOOST_LOCALE_WITH_ICU=1) - list(APPEND BOOST_SOURCES ${BOOST_ICU_SOURCES}) - else() - message(FATAL_ERROR "Unsupported value for BOOST_LOCALE_BACKEND: ${BOOST_LOCALE_BACKEND}") - endif() - - elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR - CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR - CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl64" OR - CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # For WebAssembly or asm.js - add_definitions( - -DBOOST_LOCALE_NO_WINAPI_BACKEND=1 - -DBOOST_LOCALE_NO_STD_BACKEND=1 - ) - - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/posix/converter.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/posix/numeric.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/posix/posix_backend.cpp - ) - - if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten" OR - BOOST_LOCALE_BACKEND STREQUAL "gcc" OR - BOOST_LOCALE_BACKEND STREQUAL "libiconv") - # In WebAssembly or asm.js, we rely on the version of iconv - # that is shipped with the stdlib - add_definitions(-DBOOST_LOCALE_WITH_ICONV=1) - elseif (BOOST_LOCALE_BACKEND STREQUAL "icu") - add_definitions(-DBOOST_LOCALE_WITH_ICU=1) - list(APPEND BOOST_SOURCES ${BOOST_ICU_SOURCES}) - else() - message(FATAL_ERROR "Unsupported value for BOOST_LOCALE_BACKEND: ${BOOST_LOCALE_BACKEND}") - endif() - - elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") - add_definitions( - -DBOOST_LOCALE_NO_POSIX_BACKEND=1 - -DBOOST_LOCALE_NO_STD_BACKEND=1 - ) - - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/locale/src/win32/collate.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/win32/converter.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/win32/lcid.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/win32/numeric.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/win32/win_backend.cpp - ) - - # Starting with release 0.8.2, Orthanc statically links against - # libiconv on Windows. Indeed, the "WCONV" library of Windows XP - # seems not to support properly several codepages (notably - # "Latin3", "Hebrew", and "Arabic"). Set "BOOST_LOCALE_BACKEND" - # to "wconv" to use WCONV anyway. - - if (BOOST_LOCALE_BACKEND STREQUAL "libiconv") - add_definitions(-DBOOST_LOCALE_WITH_ICONV=1) - elseif (BOOST_LOCALE_BACKEND STREQUAL "icu") - add_definitions(-DBOOST_LOCALE_WITH_ICU=1) - list(APPEND BOOST_SOURCES ${BOOST_ICU_SOURCES}) - elseif (BOOST_LOCALE_BACKEND STREQUAL "wconv") - message("Using Window's wconv") - add_definitions(-DBOOST_LOCALE_WITH_WCONV=1) - else() - message(FATAL_ERROR "Unsupported value for BOOST_LOCALE_BACKEND on Windows: ${BOOST_LOCALE_BACKEND}") - endif() - - else() - message(FATAL_ERROR "Support your platform here") - endif() - endif() - - - source_group(ThirdParty\\boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*) - -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.sh orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.sh --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.sh 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/BoostConfiguration.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,67 +0,0 @@ -#!/bin/bash - -set -e -set -u - -## Starting with version 0.6.2, Orthanc is shipped with a subset of the -## Boost libraries that is generated with the BCP tool: -## -## http://www.boost.org/doc/libs/1_54_0/tools/bcp/doc/html/index.html -## -## This script generates this subset. -## -## History: -## - Orthanc between 0.6.2 and 0.7.3: Boost 1.54.0 -## - Orthanc between 0.7.4 and 0.9.1: Boost 1.55.0 -## - Orthanc between 0.9.2 and 0.9.4: Boost 1.58.0 -## - Orthanc between 0.9.5 and 1.0.0: Boost 1.59.0 -## - Orthanc between 1.1.0 and 1.2.0: Boost 1.60.0 -## - Orthanc 1.3.0: Boost 1.64.0 -## - Orthanc 1.3.1: Boost 1.65.1 -## - Orthanc 1.3.2: Boost 1.66.0 -## - Orthanc between 1.4.0 and 1.4.2: Boost 1.67.0 -## - Orthanc between 1.5.0 and 1.5.4: Boost 1.68.0 -## - Orthanc >= 1.5.5: Boost 1.69.0 - -BOOST_VERSION=1_69_0 -ORTHANC_VERSION=1.5.6 - -rm -rf /tmp/boost_${BOOST_VERSION} -rm -rf /tmp/bcp/boost_${BOOST_VERSION} - -cd /tmp -echo "Uncompressing the sources of Boost ${BOOST_VERSION}..." -tar xfz ./boost_${BOOST_VERSION}.tar.gz - -echo "Generating the subset..." -mkdir -p /tmp/bcp/boost_${BOOST_VERSION} -bcp --boost=/tmp/boost_${BOOST_VERSION} thread system locale date_time filesystem math/special_functions algorithm uuid atomic iostreams program_options numeric/ublas geometry polygon signals2 chrono /tmp/bcp/boost_${BOOST_VERSION} - -echo "Removing documentation..." -rm -rf /tmp/bcp/boost_${BOOST_VERSION}/libs/locale/doc/html -rm -rf /tmp/bcp/boost_${BOOST_VERSION}/libs/algorithm/doc/html -rm -rf /tmp/bcp/boost_${BOOST_VERSION}/libs/geometry/doc/html -rm -rf /tmp/bcp/boost_${BOOST_VERSION}/libs/geometry/doc/doxy/doxygen_output/html -rm -rf /tmp/bcp/boost_${BOOST_VERSION}/libs/filesystem/example/ - -# https://stackoverflow.com/questions/1655372/longest-line-in-a-file -LONGEST_FILENAME=`find /tmp/bcp/ | awk '{print length, $0}' | sort -nr | head -1` -LONGEST=`echo "$LONGEST_FILENAME" | cut -d ' ' -f 1` - -echo -echo "Longest filename (${LONGEST} characters):" -echo "${LONGEST_FILENAME}" -echo - -if [ ${LONGEST} -ge 128 ]; then - echo "ERROR: Too long filename for Windows!" - echo - exit -1 -fi - -echo "Compressing the subset..." -cd /tmp/bcp -tar cfz boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz boost_${BOOST_VERSION} -ls -l boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz -md5sum boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz -readlink -f boost_${BOOST_VERSION}_bcpdigest-${ORTHANC_VERSION}.tar.gz diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/CivetwebConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/CivetwebConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/CivetwebConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/CivetwebConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_CIVETWEB) - - ## WARNING: "civetweb-1.12.tar.gz" comes with a subfolder - ## "civetweb-1.12/test/nonlatin" that cannot be removed by "hg purge - ## --all" on Windows hosts. We thus created a custom - ## "civetweb-1.12-fixed.tar.gz" as follows: - ## - ## $ cd /tmp - ## $ wget http://orthanc.osimis.io/ThirdPartyDownloads/civetweb-1.12.tar.gz - ## $ tar xvf civetweb-1.12.tar.gz - ## $ rm -rf civetweb-1.12/src/third_party/ civetweb-1.12/test/ - ## $ tar cvfz civetweb-1.12-fixed.tar.gz civetweb-1.12 - ## - - set(CIVETWEB_SOURCES_DIR ${CMAKE_BINARY_DIR}/civetweb-1.12) - set(CIVETWEB_URL "http://orthanc.osimis.io/ThirdPartyDownloads/civetweb-1.12-fixed.tar.gz") - set(CIVETWEB_MD5 "016ed7cd26cbc46b5941f0cbfb2e4ac8") - - if (IS_DIRECTORY "${CIVETWEB_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() - - DownloadPackage(${CIVETWEB_MD5} ${CIVETWEB_URL} "${CIVETWEB_SOURCES_DIR}") - - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/civetweb-1.12.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (FirstRun AND Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - include_directories( - ${CIVETWEB_SOURCES_DIR}/include - ) - - set(CIVETWEB_SOURCES - ${CIVETWEB_SOURCES_DIR}/src/civetweb.c - ) - - # New in Orthanc 1.6.0: Enable support of compression in civetweb - set_source_files_properties( - ${CIVETWEB_SOURCES} - PROPERTIES COMPILE_DEFINITIONS - "USE_ZLIB=1") - - if (ENABLE_SSL) - add_definitions( - -DNO_SSL_DL=1 - ) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") - link_libraries(dl) - endif() - - else() - add_definitions( - -DNO_SSL=1 # Remove SSL support from civetweb - ) - endif() - - source_group(ThirdParty\\Civetweb REGULAR_EXPRESSION ${CIVETWEB_SOURCES_DIR}/.*) - - add_definitions( - -DCIVETWEB_HAS_DISABLE_KEEP_ALIVE=1 - ) - -else() - CHECK_INCLUDE_FILE_CXX(civetweb.h HAVE_CIVETWEB_H) - if (NOT HAVE_CIVETWEB_H) - message(FATAL_ERROR "Please install the libcivetweb-devel package") - endif() - - cmake_reset_check_state() - set(CMAKE_REQUIRED_LIBRARIES dl pthread) - CHECK_LIBRARY_EXISTS(civetweb mg_start "" HAVE_CIVETWEB_LIB) - if (NOT HAVE_CIVETWEB_LIB) - message(FATAL_ERROR "Please install the libcivetweb-devel package") - endif() - - link_libraries(civetweb) - - add_definitions( - -DCIVETWEB_HAS_DISABLE_KEEP_ALIVE=0 - ) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Compiler.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Compiler.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Compiler.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Compiler.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -# This file sets all the compiler-related flags - -if ((CMAKE_CROSSCOMPILING AND NOT - "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") OR - "${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - # Cross-compilation necessarily implies standalone and static build - SET(STATIC_BUILD ON) - SET(STANDALONE_BUILD ON) -endif() - - -if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - # Cache the environment variables "LSB_CC" and "LSB_CXX" for further - # use by "ExternalProject" in CMake - SET(CMAKE_LSB_CC $ENV{LSB_CC} CACHE STRING "") - SET(CMAKE_LSB_CXX $ENV{LSB_CXX} CACHE STRING "") -endif() - - -if (CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long") - - # --std=c99 makes libcurl not to compile - # -pedantic gives a lot of warnings on OpenSSL - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-variadic-macros") - - if (CMAKE_CROSSCOMPILING) - # http://stackoverflow.com/a/3543845/881731 - set(CMAKE_RC_COMPILE_OBJECT " -O coff -I ") - endif() - -elseif (MSVC) - # Use static runtime under Visual Studio - # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace - # http://stackoverflow.com/a/6510446 - foreach(flag_var - CMAKE_C_FLAGS_DEBUG - CMAKE_CXX_FLAGS_DEBUG - CMAKE_C_FLAGS_RELEASE - CMAKE_CXX_FLAGS_RELEASE - CMAKE_C_FLAGS_MINSIZEREL - CMAKE_CXX_FLAGS_MINSIZEREL - CMAKE_C_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_RELWITHDEBINFO) - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") - endforeach(flag_var) - - # Add /Zm256 compiler option to Visual Studio to fix PCH errors - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm256") - - # New in Orthanc 1.5.5 - if (MSVC_MULTIPLE_PROCESSES) - # "If you omit the processMax argument in the /MP option, the - # compiler obtains the number of effective processors from the - # operating system, and then creates one process per effective - # processor" - # https://blog.kitware.com/cmake-building-with-all-your-cores/ - # https://docs.microsoft.com/en-us/cpp/build/reference/mp-build-with-multiple-processes - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") - endif() - - add_definitions( - -D_CRT_SECURE_NO_WARNINGS=1 - -D_CRT_SECURE_NO_DEPRECATE=1 - ) - - if (MSVC_VERSION LESS 1600) - # Starting with Visual Studio >= 2010 (i.e. macro _MSC_VER >= - # 1600), Microsoft ships a standard-compliant - # header. For earlier versions of Visual Studio, give access to a - # compatibility header. - # http://stackoverflow.com/a/70630/881731 - # https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h#External_links - include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio) - endif() - - link_libraries(netapi32) -endif() - - -if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - # In FreeBSD/OpenBSD, the "/usr/local/" folder contains the ports and need to be imported - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/local/include") - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib") -endif() - - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - - if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND - NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - # The "--no-undefined" linker flag makes the shared libraries - # (plugins ModalityWorklists and ServeFolders) fail to compile on - # OpenBSD, and make the PostgreSQL plugin complain about missing - # "environ" global variable in FreeBSD - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") - endif() - - if (NOT DEFINED ENABLE_PLUGINS_VERSION_SCRIPT OR - ENABLE_PLUGINS_VERSION_SCRIPT) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${ORTHANC_ROOT}/Plugins/Samples/Common/VersionScript.map") - endif() - - # Remove the "-rdynamic" option - # http://www.mail-archive.com/cmake@cmake.org/msg08837.html - set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") - link_libraries(pthread) - - if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - link_libraries(rt) - endif() - - if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND - NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - link_libraries(dl) - endif() - - if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND - NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - # The "--as-needed" linker flag is not available on FreeBSD and OpenBSD - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") - endif() - - if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND - NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - # FreeBSD/OpenBSD have just one single interface for file - # handling, which is 64bit clean, so there is no need to define macro - # for LFS (Large File Support). - # https://ohse.de/uwe/articles/lfs.html - add_definitions( - -D_LARGEFILE64_SOURCE=1 - -D_FILE_OFFSET_BITS=64 - ) - endif() - -elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if (MSVC) - message("MSVC compiler version = " ${MSVC_VERSION} "\n") - # Starting Visual Studio 2013 (version 1800), it is not possible - # to target Windows XP anymore - if (MSVC_VERSION LESS 1800) - add_definitions( - -DWINVER=0x0501 - -D_WIN32_WINNT=0x0501 - ) - endif() - else() - add_definitions( - -DWINVER=0x0501 - -D_WIN32_WINNT=0x0501 - ) - endif() - - add_definitions( - -D_CRT_SECURE_NO_WARNINGS=1 - ) - link_libraries(rpcrt4 ws2_32) - - if (CMAKE_COMPILER_IS_GNUCXX) - # Some additional C/C++ compiler flags for MinGW - SET(MINGW_NO_WARNINGS "-Wno-unused-function -Wno-unused-variable") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MINGW_NO_WARNINGS} -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MINGW_NO_WARNINGS}") - - if (DYNAMIC_MINGW_STDLIB) - else() - # This is a patch for MinGW64 - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") - endif() - - CHECK_LIBRARY_EXISTS(winpthread pthread_create "" HAVE_WIN_PTHREAD) - if (HAVE_WIN_PTHREAD) - if (DYNAMIC_MINGW_STDLIB) - else() - # This line is necessary to compile with recent versions of MinGW, - # otherwise "libwinpthread-1.dll" is not statically linked. - SET(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic") - endif() - add_definitions(-DHAVE_WIN_PTHREAD=1) - else() - add_definitions(-DHAVE_WIN_PTHREAD=0) - endif() - endif() - -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${ORTHANC_ROOT}/Plugins/Samples/Common/ExportedSymbols.list") - - add_definitions( - -D_XOPEN_SOURCE=1 - ) - link_libraries(iconv) - -elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - message("Building using Emscripten (for WebAssembly or asm.js targets)") - - # The BINARYEN_TRAP_MODE specifies what to do when divisions per - # zero (and similar conditions like integer overflows) are - # encountered: The "clamp" mode avoids throwing errors, as they - # cannot be properly catched by "try {} catch (...)" constructions. - # Setting this option to "ON" fixes error: "shared:ERROR: - # BINARYEN_TRAP_MODE is not supported by the LLVM wasm backend" if - # using the "upstream" backend of Emscripten. - if (NOT EMSCRIPTEN_SET_LLVM_WASM_BACKEND) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s BINARYEN_TRAP_MODE='\"clamp\"'") - endif() - - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'") - -elseif (CMAKE_SYSTEM_NAME STREQUAL "Android") - -else() - message("Unknown target platform: ${CMAKE_SYSTEM_NAME}") - message(FATAL_ERROR "Support your platform here") -endif() - - -if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING) - if (CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pg") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg") - else() - message(FATAL_ERROR "Don't know how to enable profiling on your configuration") - endif() -endif() - - -if (CMAKE_COMPILER_IS_GNUCXX) - # "When creating a static library using binutils (ar) and there - # exist a duplicate object name (e.g. a/Foo.cpp.o, b/Foo.cpp.o), the - # resulting static library can end up having only one of the - # duplicate objects. [...] This bug only happens if there are many - # objects." The trick consists in replacing the "r" argument - # ("replace") provided to "ar" (as used in CMake < 3.1) by the "q" - # argument ("quick append"). This is because of the fact that CMake - # will invoke "ar" several times with several batches of ".o" - # objects, and using "r" would overwrite symbols defined in - # preceding batches. https://cmake.org/Bug/view.php?id=14874 - set(CMAKE_CXX_ARCHIVE_APPEND " q ") -endif() - - -if (STATIC_BUILD) - add_definitions(-DORTHANC_STATIC=1) -else() - add_definitions(-DORTHANC_STATIC=0) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -if (NOT DEFINED ENABLE_DCMTK_NETWORKING) - set(ENABLE_DCMTK_NETWORKING ON) -endif() - -if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK) - if (DCMTK_STATIC_VERSION STREQUAL "3.6.0") - include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.0.cmake) - elseif (DCMTK_STATIC_VERSION STREQUAL "3.6.2") - include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.2.cmake) - elseif (DCMTK_STATIC_VERSION STREQUAL "3.6.4") - include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.4.cmake) - elseif (DCMTK_STATIC_VERSION STREQUAL "3.6.5") - include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfigurationStatic-3.6.5.cmake) - else() - message(FATAL_ERROR "Unsupported version of DCMTK: ${DCMTK_STATIC_VERSION}") - endif() - - - ## - ## Commands shared by all versions of DCMTK - ## - - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmdata/libsrc DCMTK_SOURCES) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/ofstd/libsrc DCMTK_SOURCES) - - LIST(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdict_orthanc.cc - ) - - if (ENABLE_DCMTK_NETWORKING) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmnet/libsrc DCMTK_SOURCES) - include_directories( - ${DCMTK_SOURCES_DIR}/dcmnet/include - ) - endif() - - if (ENABLE_DCMTK_TRANSCODING) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmimgle/libsrc DCMTK_SOURCES) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmimage/libsrc DCMTK_SOURCES) - include_directories( - ${DCMTK_SOURCES_DIR}/dcmimage/include - ) - endif() - - if (ENABLE_DCMTK_JPEG) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc DCMTK_SOURCES) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg8 DCMTK_SOURCES) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg12 DCMTK_SOURCES) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg16 DCMTK_SOURCES) - include_directories( - ${DCMTK_SOURCES_DIR}/dcmjpeg/include - ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg8 - ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg12 - ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg16 - ${DCMTK_SOURCES_DIR}/dcmimgle/include - ) - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/ddpiimpl.cc - - # Solves linking problem in WebAssembly: "wasm-ld: error: - # duplicate symbol: jaritab" (modification in Orthanc 1.5.9) - ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg8/jaricom.c - ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg12/jaricom.c - ${DCMTK_SOURCES_DIR}/dcmjpeg/libijg24/jaricom.c - ) - - if (NOT ENABLE_DCMTK_TRANSCODING) - list(REMOVE_ITEM DCMTK_SOURCES - # Disable support for encoding JPEG (modification in Orthanc 1.0.1) - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djcodece.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djencsv1.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djencbas.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djencpro.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djenclol.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djencode.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djencext.cc - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djencsps.cc - ) - endif() - endif() - - - if (ENABLE_DCMTK_JPEG_LOSSLESS) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpls/libsrc DCMTK_SOURCES) - AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpls/libcharls DCMTK_SOURCES) - include_directories( - ${DCMTK_SOURCES_DIR}/dcmjpeg/include - ${DCMTK_SOURCES_DIR}/dcmjpls/include - ${DCMTK_SOURCES_DIR}/dcmjpls/libcharls - ) - list(APPEND DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc/djrplol.cc - ) - - if (NOT ENABLE_DCMTK_TRANSCODING) - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmjpls/libsrc/djcodece.cc - - # Disable support for encoding JPEG-LS (modification in Orthanc 1.0.1) - ${DCMTK_SOURCES_DIR}/dcmjpls/libsrc/djencode.cc - ) - endif() - endif() - - - # This fixes crashes related to the destruction of the DCMTK OFLogger - # http://support.dcmtk.org/docs-snapshot/file_macros.html - add_definitions( - -DLOG4CPLUS_DISABLE_FATAL=1 - -DDCMTK_VERSION_NUMBER=${DCMTK_VERSION_NUMBER} - ) - - - if (NOT ENABLE_DCMTK_LOG) - # Disable logging internal to DCMTK - # https://groups.google.com/d/msg/orthanc-users/v2SzzAmY948/VxT1QVGiBAAJ - add_definitions( - -DDCMTK_LOG4CPLUS_DISABLE_FATAL=1 - -DDCMTK_LOG4CPLUS_DISABLE_ERROR=1 - -DDCMTK_LOG4CPLUS_DISABLE_WARN=1 - -DDCMTK_LOG4CPLUS_DISABLE_INFO=1 - -DDCMTK_LOG4CPLUS_DISABLE_DEBUG=1 - ) - endif() - - include_directories( - #${DCMTK_SOURCES_DIR} - ${DCMTK_SOURCES_DIR}/config/include - ${DCMTK_SOURCES_DIR}/ofstd/include - ${DCMTK_SOURCES_DIR}/oflog/include - ${DCMTK_SOURCES_DIR}/dcmdata/include - ) - - source_group(ThirdParty\\Dcmtk REGULAR_EXPRESSION ${DCMTK_SOURCES_DIR}/.*) - - if (STANDALONE_BUILD) - set(DCMTK_USE_EMBEDDED_DICTIONARIES 1) - set(DCMTK_DICTIONARIES - DICTIONARY_DICOM ${DCMTK_SOURCES_DIR}/dcmdata/data/dicom.dic - DICTIONARY_PRIVATE ${DCMTK_SOURCES_DIR}/dcmdata/data/private.dic - DICTIONARY_DICONDE ${DCMTK_SOURCES_DIR}/dcmdata/data/diconde.dic - ) - else() - set(DCMTK_USE_EMBEDDED_DICTIONARIES 0) - endif() - - -else() - if (CMAKE_CROSSCOMPILING AND - "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") - - CHECK_INCLUDE_FILE_CXX(dcmtk/dcmdata/dcfilefo.h HAVE_DCMTK_H) - if (NOT HAVE_DCMTK_H) - message(FATAL_ERROR "Please install the libdcmtk-dev package") - endif() - - CHECK_LIBRARY_EXISTS(dcmdata "dcmDataDict" "" HAVE_DCMTK_LIB) - if (NOT HAVE_DCMTK_LIB) - message(FATAL_ERROR "Please install the libdcmtk package") - endif() - - find_path(DCMTK_INCLUDE_DIRS dcmtk/config/osconfig.h - /usr/include - ) - - link_libraries(dcmdata dcmnet dcmjpeg oflog ofstd) - - else() - # The following line allows to manually add libraries at the - # command-line, which is necessary for Ubuntu/Debian packages - set(tmp "${DCMTK_LIBRARIES}") - include(FindDCMTK) - list(APPEND DCMTK_LIBRARIES "${tmp}") - - include_directories(${DCMTK_INCLUDE_DIRS}) - endif() - - add_definitions( - -DHAVE_CONFIG_H=1 - ) - - if (EXISTS "${DCMTK_config_INCLUDE_DIR}/cfunix.h") - set(DCMTK_CONFIGURATION_FILE "${DCMTK_config_INCLUDE_DIR}/cfunix.h") - elseif (EXISTS "${DCMTK_config_INCLUDE_DIR}/osconfig.h") # This is for Arch Linux - set(DCMTK_CONFIGURATION_FILE "${DCMTK_config_INCLUDE_DIR}/osconfig.h") - elseif (EXISTS "${DCMTK_INCLUDE_DIRS}/dcmtk/config/osconfig.h") # This is for Debian Buster - set(DCMTK_CONFIGURATION_FILE "${DCMTK_INCLUDE_DIRS}/dcmtk/config/osconfig.h") - else() - message(FATAL_ERROR "Please install libdcmtk*-dev") - endif() - - message("DCMTK configuration file: ${DCMTK_CONFIGURATION_FILE}") - - # Autodetection of the version of DCMTK - file(STRINGS - "${DCMTK_CONFIGURATION_FILE}" - DCMTK_VERSION_NUMBER1 REGEX - ".*PACKAGE_VERSION .*") - - string(REGEX REPLACE - ".*PACKAGE_VERSION.*\"([0-9]*)\\.([0-9]*)\\.([0-9]*)\"$" - "\\1\\2\\3" - DCMTK_VERSION_NUMBER - ${DCMTK_VERSION_NUMBER1}) - - set(DCMTK_USE_EMBEDDED_DICTIONARIES 0) -endif() - - -add_definitions(-DDCMTK_VERSION_NUMBER=${DCMTK_VERSION_NUMBER}) -message("DCMTK version: ${DCMTK_VERSION_NUMBER}") - - -add_definitions(-DDCMTK_USE_EMBEDDED_DICTIONARIES=${DCMTK_USE_EMBEDDED_DICTIONARIES}) -if (NOT DCMTK_USE_EMBEDDED_DICTIONARIES) - # Lookup for DICOM dictionaries, if none is specified by the user - if (DCMTK_DICTIONARY_DIR STREQUAL "") - find_path(DCMTK_DICTIONARY_DIR_AUTO dicom.dic - /usr/share/dcmtk - /usr/share/libdcmtk1 - /usr/share/libdcmtk2 - /usr/share/libdcmtk3 - /usr/share/libdcmtk4 - /usr/share/libdcmtk5 - /usr/share/libdcmtk6 - /usr/share/libdcmtk7 - /usr/share/libdcmtk8 - /usr/share/libdcmtk9 - /usr/share/libdcmtk10 - /usr/share/libdcmtk11 - /usr/share/libdcmtk12 - /usr/share/libdcmtk13 - /usr/share/libdcmtk14 - /usr/share/libdcmtk15 - /usr/share/libdcmtk16 - /usr/share/libdcmtk17 - /usr/share/libdcmtk18 - /usr/share/libdcmtk19 - /usr/share/libdcmtk20 - /usr/local/share/dcmtk - ) - - if (${DCMTK_DICTIONARY_DIR_AUTO} MATCHES "DCMTK_DICTIONARY_DIR_AUTO-NOTFOUND") - message(FATAL_ERROR "Cannot locate the DICOM dictionary on this system") - endif() - - if (CMAKE_CROSSCOMPILING AND - "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") - # Remove the sysroot prefix - file(RELATIVE_PATH tmp ${CMAKE_FIND_ROOT_PATH} ${DCMTK_DICTIONARY_DIR_AUTO}) - set(DCMTK_DICTIONARY_DIR_AUTO /${tmp} CACHE INTERNAL "") - endif() - - message("Autodetected path to the DICOM dictionaries: ${DCMTK_DICTIONARY_DIR_AUTO}") - add_definitions(-DDCMTK_DICTIONARY_DIR="${DCMTK_DICTIONARY_DIR_AUTO}") - else() - add_definitions(-DDCMTK_DICTIONARY_DIR="${DCMTK_DICTIONARY_DIR}") - endif() -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.0.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,181 +0,0 @@ -SET(DCMTK_VERSION_NUMBER 360) -SET(DCMTK_PACKAGE_VERSION "3.6.0") -SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.0.zip") -SET(DCMTK_MD5 "219ad631b82031806147e4abbfba4fa4") - -if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") - set(FirstRun OFF) -else() - set(FirstRun ON) -endif() - -DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}") - - -if (FirstRun) - # If using DCMTK 3.6.0, backport the "private.dic" file from DCMTK - # 3.6.2. This adds support for more private tags, and fixes some - # import problems with Philips MRI Achieva. - if (USE_DCMTK_362_PRIVATE_DIC) - message("Using the dictionary of private tags from DCMTK 3.6.2") - configure_file( - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2-private.dic - ${DCMTK_SOURCES_DIR}/dcmdata/data/private.dic - COPYONLY) - else() - message("Using the dictionary of private tags from DCMTK 3.6.0") - endif() - - # Patches specific to DCMTK 3.6.0 - message("Applying patch to solve vulnerability in DCMTK 3.6.0") - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - # This patch is not needed anymore thanks to the following commit - # (information sent by Jorg Riesmeier on Twitter on 2017-07-19): - # http://git.dcmtk.org/?p=dcmtk.git;a=commit;h=8df1f5e517b8629ae09088d0935c2a8dd333c76f - message("Applying patch for speed in DCMTK 3.6.0") - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-speed.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() -else() - message("The patches for DCMTK have already been applied") -endif() - - -# C_CHAR_UNSIGNED *must* be set before calling "GenerateDCMTKConfigure.cmake" -IF (CMAKE_CROSSCOMPILING) - if (CMAKE_COMPILER_IS_GNUCXX AND - CMAKE_SYSTEM_NAME STREQUAL "Windows") # MinGW - SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.") - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or asm.js - - # Check out "../WebAssembly/ArithmeticTests/" to regenerate the - # "arith.h" file - configure_file( - ${ORTHANC_ROOT}/Resources/WebAssembly/arith.h - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/arith.h - COPYONLY) - - UNSET(C_CHAR_UNSIGNED CACHE) - SET(C_CHAR_UNSIGNED 0 CACHE INTERNAL "") - - else() - message(FATAL_ERROR "Support your platform here") - endif() -ENDIF() - - -if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "") - SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "") - - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2-linux-standard-base.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (FirstRun AND Failure) - message(FATAL_ERROR "Error while patching a file") - endif() -endif() - -SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR}) -include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake) -include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake) - - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or - # asm.js The macros below are not properly discovered by DCMTK - # when using WebAssembly. Check out "../WebAssembly/arith.h" for - # how we produced these values. This step MUST be after - # "GenerateDCMTKConfigure" and before the generation of - # "osconfig.h". - UNSET(SIZEOF_VOID_P CACHE) - UNSET(SIZEOF_CHAR CACHE) - UNSET(SIZEOF_DOUBLE CACHE) - UNSET(SIZEOF_FLOAT CACHE) - UNSET(SIZEOF_INT CACHE) - UNSET(SIZEOF_LONG CACHE) - UNSET(SIZEOF_SHORT CACHE) - UNSET(SIZEOF_VOID_P CACHE) - - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") - SET(SIZEOF_CHAR 1 CACHE INTERNAL "") - SET(SIZEOF_DOUBLE 8 CACHE INTERNAL "") - SET(SIZEOF_FLOAT 4 CACHE INTERNAL "") - SET(SIZEOF_INT 4 CACHE INTERNAL "") - SET(SIZEOF_LONG 4 CACHE INTERNAL "") - SET(SIZEOF_SHORT 2 CACHE INTERNAL "") - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") -endif() - - -set(DCMTK_PACKAGE_VERSION_SUFFIX "") -set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER}) - -CONFIGURE_FILE( - ${DCMTK_SOURCES_DIR}/CMake/osconfig.h.in - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/osconfig.h) - - - -# Source for the logging facility of DCMTK -AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oflog/libsrc DCMTK_SOURCES) -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/winsock.cc - ) - -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/unixsock.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ) - - if (CMAKE_COMPILER_IS_GNUCXX) - # This is a patch for DCMTK 3.6.0 and MinGW64 - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-mingw64.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure AND FirstRun) - message(FATAL_ERROR "Error while patching a file") - endif() - endif() -endif() - - -list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc - ) diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.2.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,194 +0,0 @@ -SET(DCMTK_VERSION_NUMBER 362) -SET(DCMTK_PACKAGE_VERSION "3.6.2") -SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.2) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.2.tar.gz") -SET(DCMTK_MD5 "d219a4152772985191c9b89d75302d12") - -macro(DCMTK_UNSET) -endmacro() - -macro(DCMTK_UNSET_CACHE) -endmacro() - -set(DCMTK_BINARY_DIR ${DCMTK_SOURCES_DIR}/) -set(DCMTK_CMAKE_INCLUDE ${DCMTK_SOURCES_DIR}/) - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - set(DCMTK_WITH_THREADS OFF) # Disable thread support in wasm/asm.js -else() - set(DCMTK_WITH_THREADS ON) -endif() - -add_definitions(-DDCMTK_INSIDE_LOG4CPLUS=1) - -if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") - set(FirstRun OFF) -else() - set(FirstRun ON) -endif() - -DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}") - - -if (FirstRun) - # "3.6.2 CXX11 fails on Linux; patch suggestions included" - # https://forum.dcmtk.org/viewtopic.php?f=3&t=4637 - message("Applying patch to detect mathematic primitives in DCMTK 3.6.2 with C++11") - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - configure_file( - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-dcdict_orthanc.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdict_orthanc.cc - COPYONLY) -else() - message("The patches for DCMTK have already been applied") -endif() - - -# C_CHAR_UNSIGNED *must* be set before calling "GenerateDCMTKConfigure.cmake" -IF (CMAKE_CROSSCOMPILING) - if (CMAKE_COMPILER_IS_GNUCXX AND - CMAKE_SYSTEM_NAME STREQUAL "Windows") # MinGW - SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.") - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or asm.js - - # Check out "../WebAssembly/ArithmeticTests/" to regenerate the - # "arith.h" file - configure_file( - ${ORTHANC_ROOT}/Resources/WebAssembly/arith.h - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/arith.h - COPYONLY) - - UNSET(C_CHAR_UNSIGNED CACHE) - SET(C_CHAR_UNSIGNED 0 CACHE INTERNAL "") - - else() - message(FATAL_ERROR "Support your platform here") - endif() -ENDIF() - - -if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "") - SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "") - - if (FirstRun) - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2-linux-standard-base.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - endif() -endif() - - -SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR}) -include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake) -include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake) - - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or - # asm.js The macros below are not properly discovered by DCMTK - # when using WebAssembly. Check out "../WebAssembly/arith.h" for - # how we produced these values. This step MUST be after - # "GenerateDCMTKConfigure" and before the generation of - # "osconfig.h". - UNSET(SIZEOF_VOID_P CACHE) - UNSET(SIZEOF_CHAR CACHE) - UNSET(SIZEOF_DOUBLE CACHE) - UNSET(SIZEOF_FLOAT CACHE) - UNSET(SIZEOF_INT CACHE) - UNSET(SIZEOF_LONG CACHE) - UNSET(SIZEOF_SHORT CACHE) - UNSET(SIZEOF_VOID_P CACHE) - - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") - SET(SIZEOF_CHAR 1 CACHE INTERNAL "") - SET(SIZEOF_DOUBLE 8 CACHE INTERNAL "") - SET(SIZEOF_FLOAT 4 CACHE INTERNAL "") - SET(SIZEOF_INT 4 CACHE INTERNAL "") - SET(SIZEOF_LONG 4 CACHE INTERNAL "") - SET(SIZEOF_SHORT 2 CACHE INTERNAL "") - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") -endif() - - -set(DCMTK_PACKAGE_VERSION_SUFFIX "") -set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER}) - -CONFIGURE_FILE( - ${DCMTK_SOURCES_DIR}/CMake/osconfig.h.in - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/osconfig.h) - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - link_libraries(netapi32) # For NetWkstaUserGetInfo@12 - link_libraries(iphlpapi) # For GetAdaptersInfo@8 - - # Configure Wine if cross-compiling for Windows - if (CMAKE_COMPILER_IS_GNUCXX) - include(${DCMTK_SOURCES_DIR}/CMake/dcmtkUseWine.cmake) - FIND_PROGRAM(WINE_WINE_PROGRAM wine) - FIND_PROGRAM(WINE_WINEPATH_PROGRAM winepath) - list(APPEND DCMTK_TRY_COMPILE_REQUIRED_CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=-static") - endif() -endif() - -# This step must be after the generation of "osconfig.h" -if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - INSPECT_FUNDAMENTAL_ARITHMETIC_TYPES() -endif() - - -# Source for the logging facility of DCMTK -AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oflog/libsrc DCMTK_SOURCES) -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/winsock.cc - ) - -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/unixsock.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ) -endif() - - -#set_source_files_properties(${DCMTK_SOURCES} -# PROPERTIES COMPILE_DEFINITIONS -# "PACKAGE_VERSION=\"${DCMTK_PACKAGE_VERSION}\";PACKAGE_VERSION_NUMBER=\"${DCMTK_VERSION_NUMBER}\"") - - -# Starting with DCMTK 3.6.2, the Nagle algorithm is not disabled by -# default since this does not seem to be appropriate (anymore) for -# most modern operating systems. In order to change this default, the -# environment variable NO_TCPDELAY can be set to "1" (see envvars.txt -# for details). Alternatively, the macro DISABLE_NAGLE_ALGORITHM can -# be defined to change this setting at compilation time (see -# macros.txt for details). -# https://forum.dcmtk.org/viewtopic.php?t=4632 -add_definitions( - -DDISABLE_NAGLE_ALGORITHM=1 - ) diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.4.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,185 +0,0 @@ -SET(DCMTK_VERSION_NUMBER 364) -SET(DCMTK_PACKAGE_VERSION "3.6.4") -SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.4) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.4.tar.gz") -SET(DCMTK_MD5 "97597439a2ae7a39086066318db5f3bc") - -macro(DCMTK_UNSET) -endmacro() - -macro(DCMTK_UNSET_CACHE) -endmacro() - -set(DCMTK_BINARY_DIR ${DCMTK_SOURCES_DIR}/) -set(DCMTK_CMAKE_INCLUDE ${DCMTK_SOURCES_DIR}/) - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - set(DCMTK_WITH_THREADS OFF) # Disable thread support in wasm/asm.js -else() - set(DCMTK_WITH_THREADS ON) -endif() - -add_definitions(-DDCMTK_INSIDE_LOG4CPLUS=1) - -if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") - set(FirstRun OFF) -else() - set(FirstRun ON) -endif() - -DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}") - - -if (FirstRun) - # Apply the patches - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.4.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - configure_file( - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-dcdict_orthanc.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdict_orthanc.cc - COPYONLY) -else() - message("The patches for DCMTK have already been applied") -endif() - - -include_directories( - ${DCMTK_SOURCES_DIR}/dcmiod/include - ) - - -# C_CHAR_UNSIGNED *must* be set before calling "GenerateDCMTKConfigure.cmake" -IF (CMAKE_CROSSCOMPILING) - if (CMAKE_COMPILER_IS_GNUCXX AND - CMAKE_SYSTEM_NAME STREQUAL "Windows") # MinGW - SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.") - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or asm.js - - # Check out "../WebAssembly/ArithmeticTests/" to regenerate the - # "arith.h" file - configure_file( - ${ORTHANC_ROOT}/Resources/WebAssembly/arith.h - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/arith.h - COPYONLY) - - UNSET(C_CHAR_UNSIGNED CACHE) - SET(C_CHAR_UNSIGNED 0 CACHE INTERNAL "") - - else() - message(FATAL_ERROR "Support your platform here") - endif() -ENDIF() - - -if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "") - SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "") -endif() - - -SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR}) -include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake) -include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake) - - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or - # asm.js The macros below are not properly discovered by DCMTK - # when using WebAssembly. Check out "../WebAssembly/arith.h" for - # how we produced these values. This step MUST be after - # "GenerateDCMTKConfigure" and before the generation of - # "osconfig.h". - UNSET(SIZEOF_VOID_P CACHE) - UNSET(SIZEOF_CHAR CACHE) - UNSET(SIZEOF_DOUBLE CACHE) - UNSET(SIZEOF_FLOAT CACHE) - UNSET(SIZEOF_INT CACHE) - UNSET(SIZEOF_LONG CACHE) - UNSET(SIZEOF_SHORT CACHE) - UNSET(SIZEOF_VOID_P CACHE) - - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") - SET(SIZEOF_CHAR 1 CACHE INTERNAL "") - SET(SIZEOF_DOUBLE 8 CACHE INTERNAL "") - SET(SIZEOF_FLOAT 4 CACHE INTERNAL "") - SET(SIZEOF_INT 4 CACHE INTERNAL "") - SET(SIZEOF_LONG 4 CACHE INTERNAL "") - SET(SIZEOF_SHORT 2 CACHE INTERNAL "") - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") -endif() - - -set(DCMTK_PACKAGE_VERSION_SUFFIX "") -set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER}) - -CONFIGURE_FILE( - ${DCMTK_SOURCES_DIR}/CMake/osconfig.h.in - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/osconfig.h) - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - link_libraries(netapi32) # For NetWkstaUserGetInfo@12 - link_libraries(iphlpapi) # For GetAdaptersInfo@8 - - # Configure Wine if cross-compiling for Windows - if (CMAKE_COMPILER_IS_GNUCXX) - include(${DCMTK_SOURCES_DIR}/CMake/dcmtkUseWine.cmake) - FIND_PROGRAM(WINE_WINE_PROGRAM wine) - FIND_PROGRAM(WINE_WINEPATH_PROGRAM winepath) - list(APPEND DCMTK_TRY_COMPILE_REQUIRED_CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=-static") - endif() -endif() - -# This step must be after the generation of "osconfig.h" -if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - INSPECT_FUNDAMENTAL_ARITHMETIC_TYPES() -endif() - - -# Source for the logging facility of DCMTK -AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oflog/libsrc DCMTK_SOURCES) -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/winsock.cc - ) - -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/unixsock.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ) -endif() - - -list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc - ) - - -# Starting with DCMTK 3.6.2, the Nagle algorithm is not disabled by -# default since this does not seem to be appropriate (anymore) for -# most modern operating systems. In order to change this default, the -# environment variable NO_TCPDELAY can be set to "1" (see envvars.txt -# for details). Alternatively, the macro DISABLE_NAGLE_ALGORITHM can -# be defined to change this setting at compilation time (see -# macros.txt for details). -# https://forum.dcmtk.org/viewtopic.php?t=4632 -add_definitions( - -DDISABLE_NAGLE_ALGORITHM=1 - ) diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DcmtkConfigurationStatic-3.6.5.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,210 +0,0 @@ -SET(DCMTK_VERSION_NUMBER 365) -SET(DCMTK_PACKAGE_VERSION "3.6.5") -SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.5) -SET(DCMTK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/dcmtk-3.6.5.tar.gz") -SET(DCMTK_MD5 "e19707f64ee5695c496b9c1e48e39d07") - -macro(DCMTK_UNSET) -endmacro() - -macro(DCMTK_UNSET_CACHE) -endmacro() - -set(DCMTK_BINARY_DIR ${DCMTK_SOURCES_DIR}/) -set(DCMTK_CMAKE_INCLUDE ${DCMTK_SOURCES_DIR}/) - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - set(DCMTK_WITH_THREADS OFF) # Disable thread support in wasm/asm.js -else() - set(DCMTK_WITH_THREADS ON) -endif() - -add_definitions(-DDCMTK_INSIDE_LOG4CPLUS=1) - -if (IS_DIRECTORY "${DCMTK_SOURCES_DIR}") - set(FirstRun OFF) -else() - set(FirstRun ON) -endif() - -DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}") - - -if (FirstRun) - # Apply the patches - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.5.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - configure_file( - ${ORTHANC_ROOT}/Resources/Patches/dcmtk-dcdict_orthanc.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdict_orthanc.cc - COPYONLY) -else() - message("The patches for DCMTK have already been applied") -endif() - - -include_directories( - ${DCMTK_SOURCES_DIR}/dcmiod/include - ) - - -# C_CHAR_UNSIGNED *must* be set before calling "GenerateDCMTKConfigure.cmake" -IF (CMAKE_CROSSCOMPILING) - if (CMAKE_COMPILER_IS_GNUCXX AND - CMAKE_SYSTEM_NAME STREQUAL "Windows") # MinGW - SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.") - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or asm.js - - # Check out "../WebAssembly/ArithmeticTests/" to regenerate the - # "arith.h" file - configure_file( - ${ORTHANC_ROOT}/Resources/WebAssembly/arith.h - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/arith.h - COPYONLY) - - UNSET(C_CHAR_UNSIGNED CACHE) - SET(C_CHAR_UNSIGNED 0 CACHE INTERNAL "") - - else() - message(FATAL_ERROR "Support your platform here") - endif() -ENDIF() - - -if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "") - SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "") -endif() - - -SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR}) -include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake) -include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake) - - -if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") # WebAssembly or - # asm.js The macros below are not properly discovered by DCMTK - # when using WebAssembly. Check out "../WebAssembly/arith.h" for - # how we produced these values. This step MUST be after - # "GenerateDCMTKConfigure" and before the generation of - # "osconfig.h". - UNSET(SIZEOF_VOID_P CACHE) - UNSET(SIZEOF_CHAR CACHE) - UNSET(SIZEOF_DOUBLE CACHE) - UNSET(SIZEOF_FLOAT CACHE) - UNSET(SIZEOF_INT CACHE) - UNSET(SIZEOF_LONG CACHE) - UNSET(SIZEOF_SHORT CACHE) - UNSET(SIZEOF_VOID_P CACHE) - - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") - SET(SIZEOF_CHAR 1 CACHE INTERNAL "") - SET(SIZEOF_DOUBLE 8 CACHE INTERNAL "") - SET(SIZEOF_FLOAT 4 CACHE INTERNAL "") - SET(SIZEOF_INT 4 CACHE INTERNAL "") - SET(SIZEOF_LONG 4 CACHE INTERNAL "") - SET(SIZEOF_SHORT 2 CACHE INTERNAL "") - SET(SIZEOF_VOID_P 4 CACHE INTERNAL "") -endif() - - -set(DCMTK_PACKAGE_VERSION_SUFFIX "") -set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER}) - -CONFIGURE_FILE( - ${DCMTK_SOURCES_DIR}/CMake/osconfig.h.in - ${DCMTK_SOURCES_DIR}/config/include/dcmtk/config/osconfig.h) - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - link_libraries(netapi32) # For NetWkstaUserGetInfo@12 - link_libraries(iphlpapi) # For GetAdaptersInfo@8 - - # Configure Wine if cross-compiling for Windows - if (CMAKE_COMPILER_IS_GNUCXX) - include(${DCMTK_SOURCES_DIR}/CMake/dcmtkUseWine.cmake) - FIND_PROGRAM(WINE_WINE_PROGRAM wine) - FIND_PROGRAM(WINE_WINEPATH_PROGRAM winepath) - list(APPEND DCMTK_TRY_COMPILE_REQUIRED_CMAKE_FLAGS "-DCMAKE_EXE_LINKER_FLAGS=-static") - endif() -endif() - -# This step must be after the generation of "osconfig.h" -if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - INSPECT_FUNDAMENTAL_ARITHMETIC_TYPES() -endif() - - -# Source for the logging facility of DCMTK -AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/oflog/libsrc DCMTK_SOURCES) -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/windebap.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/winsock.cc - ) - -elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/oflog/libsrc/unixsock.cc - ${DCMTK_SOURCES_DIR}/oflog/libsrc/clfsap.cc - ) -endif() - - -list(REMOVE_ITEM DCMTK_SOURCES - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc - ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc - ) - - -# Starting with DCMTK 3.6.2, the Nagle algorithm is not disabled by -# default since this does not seem to be appropriate (anymore) for -# most modern operating systems. In order to change this default, the -# environment variable NO_TCPDELAY can be set to "1" (see envvars.txt -# for details). Alternatively, the macro DISABLE_NAGLE_ALGORITHM can -# be defined to change this setting at compilation time (see -# macros.txt for details). -# https://forum.dcmtk.org/viewtopic.php?t=4632 -add_definitions( - -DDISABLE_NAGLE_ALGORITHM=1 - ) - - -if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - # For compatibility with Windows XP, avoid using fiber-local-storage - # in log4cplus, but use thread-local-storage instead. Otherwise, - # Windows XP complains about missing "FlsGetValue()" in KERNEL32.dll - add_definitions( - -DDCMTK_LOG4CPLUS_AVOID_WIN32_FLS - ) - - if (CMAKE_COMPILER_IS_GNUCXX OR # MinGW - "${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") # MSVC for 32bit (*) - - # (*) With multithreaded logging enabled, Visual Studio 2008 fails - # with error: ".\dcmtk-3.6.5\oflog\libsrc\globinit.cc(422) : error - # C2664: 'dcmtk::log4cplus::thread::impl::tls_init' : cannot - # convert parameter 1 from 'void (__stdcall *)(void *)' to - # 'dcmtk::log4cplus::thread::impl::tls_init_cleanup_func_type'" - # None of the functions with this name in scope match the target type - - add_definitions( - -DDCMTK_LOG4CPLUS_SINGLE_THREADED - ) - endif() -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DownloadPackage.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DownloadPackage.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DownloadPackage.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/DownloadPackage.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -macro(GetUrlFilename TargetVariable Url) - string(REGEX REPLACE "^.*/" "" ${TargetVariable} "${Url}") -endmacro() - - -macro(GetUrlExtension TargetVariable Url) - #string(REGEX REPLACE "^.*/[^.]*\\." "" TMP "${Url}") - string(REGEX REPLACE "^.*\\." "" TMP "${Url}") - string(TOLOWER "${TMP}" "${TargetVariable}") -endmacro() - - - -## -## Setup the patch command-line tool -## - -if (NOT ORTHANC_DISABLE_PATCH) - if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe) - if (NOT EXISTS ${PATCH_EXECUTABLE}) - message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc") - endif() - - else () - find_program(PATCH_EXECUTABLE patch) - if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the 'patch' standard command-line tool") - endif() - endif() -endif() - - - -## -## Check the existence of the required decompression tools -## - -if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - find_program(ZIP_EXECUTABLE 7z - PATHS - "$ENV{ProgramFiles}/7-Zip" - "$ENV{ProgramW6432}/7-Zip" - ) - - if (${ZIP_EXECUTABLE} MATCHES "ZIP_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") - endif() - -else() - find_program(UNZIP_EXECUTABLE unzip) - if (${UNZIP_EXECUTABLE} MATCHES "UNZIP_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the 'unzip' package") - endif() - - find_program(TAR_EXECUTABLE tar) - if (${TAR_EXECUTABLE} MATCHES "TAR_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the 'tar' package") - endif() - - find_program(GUNZIP_EXECUTABLE gunzip) - if (${GUNZIP_EXECUTABLE} MATCHES "GUNZIP_EXECUTABLE-NOTFOUND") - message(FATAL_ERROR "Please install the 'gzip' package") - endif() -endif() - - -macro(DownloadFile MD5 Url) - GetUrlFilename(TMP_FILENAME "${Url}") - - set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}") - if (NOT EXISTS "${TMP_PATH}") - message("Downloading ${Url}") - - # This fixes issue 6: "I think cmake shouldn't download the - # packages which are not in the system, it should stop and let - # user know." - # https://code.google.com/p/orthanc/issues/detail?id=6 - if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) - message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") - endif() - - if ("${MD5}" STREQUAL "no-check") - message(WARNING "Not checking the MD5 of: ${Url}") - file(DOWNLOAD "${Url}" "${TMP_PATH}" - SHOW_PROGRESS TIMEOUT 300 INACTIVITY_TIMEOUT 60 - STATUS Failure) - else() - file(DOWNLOAD "${Url}" "${TMP_PATH}" - SHOW_PROGRESS TIMEOUT 300 INACTIVITY_TIMEOUT 60 - EXPECTED_MD5 "${MD5}" STATUS Failure) - endif() - - list(GET Failure 0 Status) - if (NOT Status EQUAL 0) - message(FATAL_ERROR "Cannot download file: ${Url}") - endif() - - else() - message("Using local copy of ${Url}") - - if ("${MD5}" STREQUAL "no-check") - message(WARNING "Not checking the MD5 of: ${Url}") - else() - file(MD5 ${TMP_PATH} ActualMD5) - if (NOT "${ActualMD5}" STREQUAL "${MD5}") - message(FATAL_ERROR "The MD5 hash of a previously download file is invalid: ${TMP_PATH}") - endif() - endif() - endif() -endmacro() - - -macro(DownloadPackage MD5 Url TargetDirectory) - if (NOT IS_DIRECTORY "${TargetDirectory}") - DownloadFile("${MD5}" "${Url}") - - GetUrlExtension(TMP_EXTENSION "${Url}") - #message(${TMP_EXTENSION}) - message("Uncompressing ${TMP_FILENAME}") - - if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - # How to silently extract files using 7-zip - # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly - - if (("${TMP_EXTENSION}" STREQUAL "gz") OR - ("${TMP_EXTENSION}" STREQUAL "tgz") OR - ("${TMP_EXTENSION}" STREQUAL "xz")) - execute_process( - COMMAND ${ZIP_EXECUTABLE} e -y ${TMP_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - if ("${TMP_EXTENSION}" STREQUAL "tgz") - string(REGEX REPLACE ".tgz$" ".tar" TMP_FILENAME2 "${TMP_FILENAME}") - elseif ("${TMP_EXTENSION}" STREQUAL "gz") - string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") - elseif ("${TMP_EXTENSION}" STREQUAL "xz") - string(REGEX REPLACE ".xz" "" TMP_FILENAME2 "${TMP_FILENAME}") - endif() - - execute_process( - COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_FILENAME2} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - elseif ("${TMP_EXTENSION}" STREQUAL "zip") - execute_process( - COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_PATH} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - else() - message(FATAL_ERROR "Unsupported package extension: ${TMP_EXTENSION}") - endif() - - else() - if ("${TMP_EXTENSION}" STREQUAL "zip") - execute_process( - COMMAND sh -c "${UNZIP_EXECUTABLE} -q ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - elseif (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) - #message("tar xvfz ${TMP_PATH}") - execute_process( - COMMAND sh -c "${TAR_EXECUTABLE} xfz ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - elseif ("${TMP_EXTENSION}" STREQUAL "bz2") - execute_process( - COMMAND sh -c "${TAR_EXECUTABLE} xfj ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - elseif ("${TMP_EXTENSION}" STREQUAL "xz") - execute_process( - COMMAND sh -c "${TAR_EXECUTABLE} xf ${TMP_PATH}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - else() - message(FATAL_ERROR "Unsupported package extension: ${TMP_EXTENSION}") - endif() - endif() - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - if (NOT IS_DIRECTORY "${TargetDirectory}") - message(FATAL_ERROR "The package was not uncompressed at the proper location. Check the CMake instructions.") - endif() - endif() -endmacro() - - - -macro(DownloadCompressedFile MD5 Url TargetFile) - message(${MD5}) - message(${Url}) - message(${TargetFile}) - if (NOT EXISTS "${TargetFile}") - DownloadFile("${MD5}" "${Url}") - - GetUrlExtension(TMP_EXTENSION "${Url}") - #message(${TMP_EXTENSION}) - message("Uncompressing ${TMP_FILENAME}") - - if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - # How to silently extract files using 7-zip - # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly - - if ("${TMP_EXTENSION}" STREQUAL "gz") - execute_process( - # "-so" writes uncompressed file to stdout - COMMAND ${ZIP_EXECUTABLE} e -so -y ${TMP_PATH} - OUTPUT_FILE "${TargetFile}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - else() - message(FATAL_ERROR "Unsupported file extension: ${TMP_EXTENSION}") - endif() - - else() - if ("${TMP_EXTENSION}" STREQUAL "gz") - execute_process( - COMMAND sh -c "${GUNZIP_EXECUTABLE} -c ${TMP_PATH}" - OUTPUT_FILE "${TargetFile}" - RESULT_VARIABLE Failure - ) - else() - message(FATAL_ERROR "Unsupported file extension: ${TMP_EXTENSION}") - endif() - endif() - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - if (NOT EXISTS "${TargetFile}") - message(FATAL_ERROR "The file was not uncompressed at the proper location. Check the CMake instructions.") - endif() - endif() -endmacro() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/GoogleTestConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/GoogleTestConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/GoogleTestConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/GoogleTestConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -if (USE_GOOGLE_TEST_DEBIAN_PACKAGE) - find_path(GOOGLE_TEST_DEBIAN_SOURCES_DIR - NAMES src/gtest-all.cc - PATHS - ${CROSSTOOL_NG_IMAGE}/usr/src/gtest - ${CROSSTOOL_NG_IMAGE}/usr/src/googletest/googletest - PATH_SUFFIXES src - ) - - find_path(GOOGLE_TEST_DEBIAN_INCLUDE_DIR - NAMES gtest.h - PATHS - ${CROSSTOOL_NG_IMAGE}/usr/include/gtest - ) - - message("Path to the Debian Google Test sources: ${GOOGLE_TEST_DEBIAN_SOURCES_DIR}") - message("Path to the Debian Google Test includes: ${GOOGLE_TEST_DEBIAN_INCLUDE_DIR}") - - set(GOOGLE_TEST_SOURCES - ${GOOGLE_TEST_DEBIAN_SOURCES_DIR}/src/gtest-all.cc - ) - - include_directories(${GOOGLE_TEST_DEBIAN_SOURCES_DIR}) - - if (NOT EXISTS ${GOOGLE_TEST_SOURCES} OR - NOT EXISTS ${GOOGLE_TEST_DEBIAN_INCLUDE_DIR}/gtest.h) - message(FATAL_ERROR "Please install the libgtest-dev package") - endif() - -elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST) - set(GOOGLE_TEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/googletest-release-1.8.1) - set(GOOGLE_TEST_URL "http://orthanc.osimis.io/ThirdPartyDownloads/gtest-1.8.1.tar.gz") - set(GOOGLE_TEST_MD5 "2e6fbeb6a91310a16efe181886c59596") - - DownloadPackage(${GOOGLE_TEST_MD5} ${GOOGLE_TEST_URL} "${GOOGLE_TEST_SOURCES_DIR}") - - include_directories( - ${GOOGLE_TEST_SOURCES_DIR}/googletest - ${GOOGLE_TEST_SOURCES_DIR}/googletest/include - ${GOOGLE_TEST_SOURCES_DIR} - ) - - set(GOOGLE_TEST_SOURCES - ${GOOGLE_TEST_SOURCES_DIR}/googletest/src/gtest-all.cc - ) - - # https://code.google.com/p/googletest/issues/detail?id=412 - if (MSVC) # VS2012 does not support tuples correctly yet - add_definitions(/D _VARIADIC_MAX=10) - endif() - - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - add_definitions(-DGTEST_HAS_CLONE=0) - endif() - - source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GOOGLE_TEST_SOURCES_DIR}/.*) - -else() - include(FindGTest) - if (NOT GTEST_FOUND) - message(FATAL_ERROR "Unable to find GoogleTest") - endif() - - include_directories(${GTEST_INCLUDE_DIRS}) - - # The variable GTEST_LIBRARIES contains the shared library of - # Google Test, create an alias for more uniformity - set(GOOGLE_TEST_LIBRARIES ${GTEST_LIBRARIES}) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/JsonCppConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/JsonCppConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/JsonCppConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/JsonCppConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -set(JSONCPP_CXX11 OFF) - -if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP) - if (USE_LEGACY_JSONCPP) - set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-0.10.7) - set(JSONCPP_URL "http://orthanc.osimis.io/ThirdPartyDownloads/jsoncpp-0.10.7.tar.gz") - set(JSONCPP_MD5 "3a8072ca6a1fa9cbaf7715ae625f134f") - add_definitions(-DORTHANC_LEGACY_JSONCPP=1) - else() - set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-1.8.4) - set(JSONCPP_URL "http://orthanc.osimis.io/ThirdPartyDownloads/jsoncpp-1.8.4.tar.gz") - set(JSONCPP_MD5 "fa47a3ab6b381869b6a5f20811198662") - add_definitions(-DORTHANC_LEGACY_JSONCPP=0) - set(JSONCPP_CXX11 ON) - endif() - - DownloadPackage(${JSONCPP_MD5} ${JSONCPP_URL} "${JSONCPP_SOURCES_DIR}") - - set(JSONCPP_SOURCES - ${JSONCPP_SOURCES_DIR}/src/lib_json/json_reader.cpp - ${JSONCPP_SOURCES_DIR}/src/lib_json/json_value.cpp - ${JSONCPP_SOURCES_DIR}/src/lib_json/json_writer.cpp - ) - - include_directories( - ${JSONCPP_SOURCES_DIR}/include - ) - - if (NOT ENABLE_LOCALE) - add_definitions(-DJSONCPP_NO_LOCALE_SUPPORT=1) - endif() - - source_group(ThirdParty\\JsonCpp REGULAR_EXPRESSION ${JSONCPP_SOURCES_DIR}/.*) - -else() - find_path(JSONCPP_INCLUDE_DIR json/reader.h - /usr/include/jsoncpp - /usr/local/include/jsoncpp - ) - - message("JsonCpp include dir: ${JSONCPP_INCLUDE_DIR}") - include_directories(${JSONCPP_INCLUDE_DIR}) - link_libraries(jsoncpp) - - CHECK_INCLUDE_FILE_CXX(${JSONCPP_INCLUDE_DIR}/json/reader.h HAVE_JSONCPP_H) - if (NOT HAVE_JSONCPP_H) - message(FATAL_ERROR "Please install the libjsoncpp-dev package") - endif() - - # Switch to the C++11 standard if the version of JsonCpp is 1.y.z - if (EXISTS ${JSONCPP_INCLUDE_DIR}/json/version.h) - file(STRINGS - "${JSONCPP_INCLUDE_DIR}/json/version.h" - JSONCPP_VERSION_MAJOR1 REGEX - ".*define JSONCPP_VERSION_MAJOR.*") - - if (NOT JSONCPP_VERSION_MAJOR1) - message(FATAL_ERROR "Unable to extract the major version of JsonCpp") - endif() - - string(REGEX REPLACE - ".*JSONCPP_VERSION_MAJOR.*([0-9]+)$" "\\1" - JSONCPP_VERSION_MAJOR ${JSONCPP_VERSION_MAJOR1}) - message("JsonCpp major version: ${JSONCPP_VERSION_MAJOR}") - - if (JSONCPP_VERSION_MAJOR GREATER 0) - set(JSONCPP_CXX11 ON) - endif() - else() - message("Unable to detect the major version of JsonCpp, assuming < 1.0.0") - endif() -endif() - - -if (JSONCPP_CXX11) - # Osimis has encountered problems when this macro is left at its - # default value (1000), so we increase this limit - # https://gitlab.kitware.com/third-party/jsoncpp/commit/56df2068470241f9043b676bfae415ed62a0c172 - add_definitions(-DJSONCPP_DEPRECATED_STACK_LIMIT=5000) - - if (CMAKE_COMPILER_IS_GNUCXX) - message("Switching to C++11 standard in gcc, as version of JsonCpp is >= 1.0.0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wno-deprecated-declarations") - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - message("Switching to C++11 standard in clang, as version of JsonCpp is >= 1.0.0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-declarations") - endif() -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibCurlConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibCurlConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibCurlConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibCurlConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,339 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_CURL) - SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.64.0) - SET(CURL_URL "http://orthanc.osimis.io/ThirdPartyDownloads/curl-7.64.0.tar.gz") - SET(CURL_MD5 "a026740d599a32bcbbe6e70679397899") - - if (IS_DIRECTORY "${CURL_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() - - DownloadPackage(${CURL_MD5} ${CURL_URL} "${CURL_SOURCES_DIR}") - - if (FirstRun) - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/curl-7.64.0-cmake.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - endif() - - include_directories( - ${CURL_SOURCES_DIR}/include - ) - - AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib CURL_SOURCES) - AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vauth CURL_SOURCES) - AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vtls CURL_SOURCES) - source_group(ThirdParty\\LibCurl REGULAR_EXPRESSION ${CURL_SOURCES_DIR}/.*) - - add_definitions( - -DBUILDING_LIBCURL=1 - -DCURL_STATICLIB=1 - -DCURL_DISABLE_LDAPS=1 - -DCURL_DISABLE_LDAP=1 - -DCURL_DISABLE_DICT=1 - -DCURL_DISABLE_FILE=1 - -DCURL_DISABLE_FTP=1 - -DCURL_DISABLE_GOPHER=1 - -DCURL_DISABLE_LDAP=1 - -DCURL_DISABLE_LDAPS=1 - -DCURL_DISABLE_POP3=1 - #-DCURL_DISABLE_PROXY=1 - -DCURL_DISABLE_RTSP=1 - -DCURL_DISABLE_TELNET=1 - -DCURL_DISABLE_TFTP=1 - ) - - if (ENABLE_SSL) - add_definitions( - #-DHAVE_LIBSSL=1 - -DUSE_OPENSSL=1 - -DHAVE_OPENSSL_ENGINE_H=1 - -DUSE_SSLEAY=1 - ) - endif() - - if (NOT EXISTS "${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h") - #file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "") - - file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h "#include \"../vauth.h\"\n") - file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/digest.h "#include \"../digest.h\"\n") - file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/ntlm.h "#include \"../ntlm.h\"\n") - file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vtls/vtls.h "#include \"../../vtls/vtls.h\"\n") - - file(GLOB CURL_LIBS_HEADERS ${CURL_SOURCES_DIR}/lib/*.h) - foreach (header IN LISTS CURL_LIBS_HEADERS) - get_filename_component(filename ${header} NAME) - file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/${filename} "#include \"../${filename}\"\n") - file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/${filename} "#include \"../${filename}\"\n") - endforeach() - endif() - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - SET(TMP_OS "x86_64") - else() - SET(TMP_OS "x86") - endif() - - set_property( - SOURCE ${CURL_SOURCES} - PROPERTY COMPILE_DEFINITIONS "HAVE_CONFIG_H=1;OS=\"${TMP_OS}\"" - ) - - include(${CURL_SOURCES_DIR}/CMake/Macros.cmake) - - # WARNING: Do *not* reorder the "check_include_file_concat()" below! - check_include_file_concat("stdio.h" HAVE_STDIO_H) - check_include_file_concat("inttypes.h" HAVE_INTTYPES_H) - check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) - check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) - check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H) - check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H) - check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H) - check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H) - check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H) - check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H) - check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H) - check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H) - check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H) - check_include_file_concat("sys/uio.h" HAVE_SYS_UIO_H) - check_include_file_concat("sys/un.h" HAVE_SYS_UN_H) - check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H) - check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H) - check_include_file_concat("alloca.h" HAVE_ALLOCA_H) - check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) - check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H) - check_include_file_concat("assert.h" HAVE_ASSERT_H) - check_include_file_concat("crypto.h" HAVE_CRYPTO_H) - check_include_file_concat("des.h" HAVE_DES_H) - check_include_file_concat("err.h" HAVE_ERR_H) - check_include_file_concat("errno.h" HAVE_ERRNO_H) - check_include_file_concat("fcntl.h" HAVE_FCNTL_H) - check_include_file_concat("idn2.h" HAVE_IDN2_H) - check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) - check_include_file_concat("io.h" HAVE_IO_H) - check_include_file_concat("krb.h" HAVE_KRB_H) - check_include_file_concat("libgen.h" HAVE_LIBGEN_H) - check_include_file_concat("limits.h" HAVE_LIMITS_H) - check_include_file_concat("locale.h" HAVE_LOCALE_H) - check_include_file_concat("net/if.h" HAVE_NET_IF_H) - check_include_file_concat("netdb.h" HAVE_NETDB_H) - check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H) - check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H) - - check_include_file_concat("pem.h" HAVE_PEM_H) - check_include_file_concat("poll.h" HAVE_POLL_H) - check_include_file_concat("pwd.h" HAVE_PWD_H) - check_include_file_concat("rsa.h" HAVE_RSA_H) - check_include_file_concat("setjmp.h" HAVE_SETJMP_H) - check_include_file_concat("sgtty.h" HAVE_SGTTY_H) - check_include_file_concat("signal.h" HAVE_SIGNAL_H) - check_include_file_concat("ssl.h" HAVE_SSL_H) - check_include_file_concat("stdbool.h" HAVE_STDBOOL_H) - check_include_file_concat("stdint.h" HAVE_STDINT_H) - check_include_file_concat("stdio.h" HAVE_STDIO_H) - check_include_file_concat("stdlib.h" HAVE_STDLIB_H) - check_include_file_concat("string.h" HAVE_STRING_H) - check_include_file_concat("strings.h" HAVE_STRINGS_H) - check_include_file_concat("stropts.h" HAVE_STROPTS_H) - check_include_file_concat("termio.h" HAVE_TERMIO_H) - check_include_file_concat("termios.h" HAVE_TERMIOS_H) - check_include_file_concat("time.h" HAVE_TIME_H) - check_include_file_concat("unistd.h" HAVE_UNISTD_H) - check_include_file_concat("utime.h" HAVE_UTIME_H) - check_include_file_concat("x509.h" HAVE_X509_H) - - check_include_file_concat("process.h" HAVE_PROCESS_H) - check_include_file_concat("stddef.h" HAVE_STDDEF_H) - check_include_file_concat("dlfcn.h" HAVE_DLFCN_H) - check_include_file_concat("malloc.h" HAVE_MALLOC_H) - check_include_file_concat("memory.h" HAVE_MEMORY_H) - check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) - check_include_file_concat("stdint.h" HAVE_STDINT_H) - check_include_file_concat("sockio.h" HAVE_SOCKIO_H) - check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) - - check_type_size("size_t" SIZEOF_SIZE_T) - check_type_size("ssize_t" SIZEOF_SSIZE_T) - check_type_size("long long" SIZEOF_LONG_LONG) - check_type_size("long" SIZEOF_LONG) - check_type_size("short" SIZEOF_SHORT) - check_type_size("int" SIZEOF_INT) - check_type_size("__int64" SIZEOF___INT64) - check_type_size("long double" SIZEOF_LONG_DOUBLE) - check_type_size("time_t" SIZEOF_TIME_T) - check_type_size("off_t" SIZEOF_OFF_T) - check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T) - - check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME) - check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) - # poll on macOS is unreliable, it first did not exist, then was broken until - # fixed in 10.9 only to break again in 10.12. - if(NOT APPLE) - check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL) - endif() - check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT) - check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP) - check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR) - check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R) - check_symbol_exists(strftime "${CURL_INCLUDES}" HAVE_STRFTIME) - check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) - check_symbol_exists(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP) - check_symbol_exists(stricmp "${CURL_INCLUDES}" HAVE_STRICMP) - check_symbol_exists(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI) - check_symbol_exists(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI) - check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM) - if(NOT HAVE_STRNCMPI) - set(HAVE_STRCMPI) - endif(NOT HAVE_STRNCMPI) - - check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR) - check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R) - check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY) - check_symbol_exists(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR) - check_symbol_exists(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA) - check_symbol_exists(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R) - check_symbol_exists(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR) - check_symbol_exists(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR) - check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) - check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET) - check_symbol_exists(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF) - check_symbol_exists(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP) - check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R) - check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT) - check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID) - check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID) - check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME) - check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R) - check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R) - - check_symbol_exists(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME) - check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) - - check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC) - check_symbol_exists(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO) - if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) - set(HAVE_SIGNAL 1) - endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) - check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) - check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL) - check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64) - check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) - check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) - check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) - check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK) - check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) - check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) - check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS) - check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) - check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) - check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) - check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) - check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) - check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE) - check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) - check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) - check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) - check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) - - if(HAVE_SIZEOF_LONG_LONG) - set(HAVE_LONGLONG 1) - set(HAVE_LL 1) - endif(HAVE_SIZEOF_LONG_LONG) - - check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) - check_function_exists(gethostname HAVE_GETHOSTNAME) - - check_include_file_concat("pthread.h" HAVE_PTHREAD_H) - check_symbol_exists(recv "sys/socket.h" HAVE_RECV) - check_symbol_exists(send "sys/socket.h" HAVE_SEND) - - check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) - - list(APPEND CMAKE_REQUIRED_INCLUDES "${CURL_SOURCES_DIR}/include") - set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h") - check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) - - add_definitions(-DHAVE_GLIBC_STRERROR_R=1) - - include(${CURL_SOURCES_DIR}/CMake/OtherTests.cmake) - - foreach(CURL_TEST - HAVE_FCNTL_O_NONBLOCK - HAVE_IOCTLSOCKET - HAVE_IOCTLSOCKET_CAMEL - HAVE_IOCTLSOCKET_CAMEL_FIONBIO - HAVE_IOCTLSOCKET_FIONBIO - HAVE_IOCTL_FIONBIO - HAVE_IOCTL_SIOCGIFADDR - HAVE_SETSOCKOPT_SO_NONBLOCK - HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID - TIME_WITH_SYS_TIME - HAVE_O_NONBLOCK - HAVE_GETHOSTBYADDR_R_5 - HAVE_GETHOSTBYADDR_R_7 - HAVE_GETHOSTBYADDR_R_8 - HAVE_GETHOSTBYADDR_R_5_REENTRANT - HAVE_GETHOSTBYADDR_R_7_REENTRANT - HAVE_GETHOSTBYADDR_R_8_REENTRANT - HAVE_GETHOSTBYNAME_R_3 - HAVE_GETHOSTBYNAME_R_5 - HAVE_GETHOSTBYNAME_R_6 - HAVE_GETHOSTBYNAME_R_3_REENTRANT - HAVE_GETHOSTBYNAME_R_5_REENTRANT - HAVE_GETHOSTBYNAME_R_6_REENTRANT - HAVE_SOCKLEN_T - HAVE_IN_ADDR_T - HAVE_BOOL_T - STDC_HEADERS - RETSIGTYPE_TEST - HAVE_INET_NTOA_R_DECL - HAVE_INET_NTOA_R_DECL_REENTRANT - HAVE_GETADDRINFO - HAVE_FILE_OFFSET_BITS - ) - curl_internal_test(${CURL_TEST}) - endforeach(CURL_TEST) - - configure_file( - ${CURL_SOURCES_DIR}/lib/curl_config.h.cmake - ${CURL_SOURCES_DIR}/lib/curl_config.h - ) - endif() - -elseif (CMAKE_CROSSCOMPILING AND - "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") - - CHECK_INCLUDE_FILE_CXX(curl/curl.h HAVE_CURL_H) - if (NOT HAVE_CURL_H) - message(FATAL_ERROR "Please install the libcurl-dev package") - endif() - - CHECK_LIBRARY_EXISTS(curl "curl_easy_init" "" HAVE_CURL_LIB) - if (NOT HAVE_CURL_LIB) - message(FATAL_ERROR "Please install the libcurl package") - endif() - - link_libraries(curl) - -else() - include(FindCURL) - include_directories(${CURL_INCLUDE_DIRS}) - link_libraries(${CURL_LIBRARIES}) - - if (NOT ${CURL_FOUND}) - message(FATAL_ERROR "Unable to find LibCurl") - endif() -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIconvConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIconvConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIconvConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIconvConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -message("Using libiconv") - -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBICONV) - set(LIBICONV_SOURCES_DIR ${CMAKE_BINARY_DIR}/libiconv-1.15) - set(LIBICONV_URL "http://orthanc.osimis.io/ThirdPartyDownloads/libiconv-1.15.tar.gz") - set(LIBICONV_MD5 "ace8b5f2db42f7b3b3057585e80d9808") - - DownloadPackage(${LIBICONV_MD5} ${LIBICONV_URL} "${LIBICONV_SOURCES_DIR}") - - # Disable the support of libiconv that is shipped by default with - # the C standard library on Linux. Setting this macro redirects - # calls from "iconv*()" to "libiconv*()" by defining macros in the - # C headers of "libiconv-1.15". - add_definitions(-DLIBICONV_PLUG=1) - - # https://groups.google.com/d/msg/android-ndk/AS1nkxnk6m4/EQm09hD1tigJ - add_definitions( - -DBUILDING_LIBICONV=1 - -DIN_LIBRARY=1 - -DLIBDIR="" - -DICONV_CONST= - #-DENABLE_EXTRA=1 - ) - - configure_file( - ${LIBICONV_SOURCES_DIR}/srclib/localcharset.h - ${LIBICONV_SOURCES_DIR}/include - COPYONLY) - - set(HAVE_VISIBILITY 0) - set(ICONV_CONST ${ICONV_CONST}) - set(USE_MBSTATE_T 1) - set(BROKEN_WCHAR_H 0) - set(EILSEQ) - set(HAVE_WCHAR_T 1) - configure_file( - ${LIBICONV_SOURCES_DIR}/include/iconv.h.build.in - ${LIBICONV_SOURCES_DIR}/include/iconv.h - ) - unset(HAVE_VISIBILITY) - unset(ICONV_CONST) - unset(USE_MBSTATE_T) - unset(BROKEN_WCHAR_H) - unset(EILSEQ) - unset(HAVE_WCHAR_T) - - if (NOT EXISTS ${LIBICONV_SOURCES_DIR}/include/config.h) - # Create an empty "config.h" for libiconv - file(WRITE ${LIBICONV_SOURCES_DIR}/include/config.h "") - endif() - - include_directories( - ${LIBICONV_SOURCES_DIR}/include - ) - - set(LIBICONV_SOURCES - ${LIBICONV_SOURCES_DIR}/lib/iconv.c - ${LIBICONV_SOURCES_DIR}/lib/relocatable.c - ${LIBICONV_SOURCES_DIR}/libcharset/lib/localcharset.c - ${LIBICONV_SOURCES_DIR}/libcharset/lib/relocatable.c - ) - - source_group(ThirdParty\\libiconv REGULAR_EXPRESSION ${LIBICONV_SOURCES_DIR}/.*) - - if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - add_definitions(-DHAVE_WORKING_O_NOFOLLOW=0) - else() - add_definitions(-DHAVE_WORKING_O_NOFOLLOW=1) - endif() - -else() - CHECK_INCLUDE_FILE_CXX(iconv.h HAVE_ICONV_H) - if (NOT HAVE_ICONV_H) - message(FATAL_ERROR "Please install the libiconv-dev package") - endif() - - # Check whether the support for libiconv is bundled within the - # standard C library - CHECK_FUNCTION_EXISTS(iconv_open HAVE_ICONV_LIB) - if (NOT HAVE_ICONV_LIB) - # No builtin support for libiconv, try and find an external library. - # Open question: Does this make sense on any platform? - CHECK_LIBRARY_EXISTS(iconv iconv_open "" HAVE_ICONV_LIB_2) - if (NOT HAVE_ICONV_LIB_2) - message(FATAL_ERROR "Please install the libiconv-dev package") - else() - link_libraries(iconv) - endif() - endif() -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIcuConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIcuConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIcuConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibIcuConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ - -# Check out: ../ThirdParty/icu/README.txt - -# http://userguide.icu-project.org/packaging -# http://userguide.icu-project.org/howtouseicu - -message("Using libicu") - -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBICU) - include(${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/icu/Version.cmake) - DownloadPackage(${LIBICU_MD5} ${LIBICU_URL} "${LIBICU_SOURCES_DIR}") - - # Use the gzip-compressed data - DownloadFile(${LIBICU_DATA_COMPRESSED_MD5} ${LIBICU_DATA_URL}) - set(LIBICU_RESOURCES - LIBICU_DATA ${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${LIBICU_DATA} - ) - - set_source_files_properties( - ${CMAKE_BINARY_DIR}/${LIBICU_DATA} - PROPERTIES COMPILE_DEFINITIONS "char16_t=uint16_t" - ) - - include_directories(BEFORE - ${LIBICU_SOURCES_DIR}/source/common - ${LIBICU_SOURCES_DIR}/source/i18n - ) - - aux_source_directory(${LIBICU_SOURCES_DIR}/source/common LIBICU_SOURCES) - aux_source_directory(${LIBICU_SOURCES_DIR}/source/i18n LIBICU_SOURCES) - - add_definitions( - #-DU_COMBINED_IMPLEMENTATION - #-DU_DEF_ICUDATA_ENTRY_POINT=icudt63l_dat - #-DU_LIB_SUFFIX_C_NAME=l - - #-DUCONFIG_NO_SERVICE=1 - -DU_COMMON_IMPLEMENTATION - -DU_STATIC_IMPLEMENTATION - -DU_ENABLE_DYLOAD=0 - -DU_HAVE_STD_STRING=1 - -DU_I18N_IMPLEMENTATION - -DU_IO_IMPLEMENTATION - -DU_STATIC_IMPLEMENTATION=1 - #-DU_CHARSET_IS_UTF8 - -DUNISTR_FROM_STRING_EXPLICIT= - - -DORTHANC_STATIC_ICU=1 - -DORTHANC_ICU_DATA_MD5="${LIBICU_DATA_UNCOMPRESSED_MD5}" - ) - - if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - set_source_files_properties( - ${LIBICU_SOURCES_DIR}/source/common/locmap.c - PROPERTIES COMPILE_DEFINITIONS "LOCALE_SNAME=0x0000005c" - ) - endif() - - source_group(ThirdParty\\libicu REGULAR_EXPRESSION ${LIBICU_SOURCES_DIR}/.*) - -else() - CHECK_INCLUDE_FILE_CXX(unicode/uvernum.h HAVE_ICU_H) - if (NOT HAVE_ICU_H) - message(FATAL_ERROR "Please install the libicu-dev package") - endif() - - find_library(LIBICU_PATH_1 NAMES icuuc) - find_library(LIBICU_PATH_2 NAMES icui18n) - - if (NOT LIBICU_PATH_1 OR - NOT LIBICU_PATH_2) - message(FATAL_ERROR "Please install the libicu-dev package") - else() - link_libraries(${LIBICU_PATH_1} ${LIBICU_PATH_2}) - endif() - - add_definitions( - -DORTHANC_STATIC_ICU=0 - ) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibJpegConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibJpegConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibJpegConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibJpegConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG) - set(LIBJPEG_SOURCES_DIR ${CMAKE_BINARY_DIR}/jpeg-9c) - DownloadPackage( - "93c62597eeef81a84d988bccbda1e990" - "http://orthanc.osimis.io/ThirdPartyDownloads/jpegsrc.v9c.tar.gz" - "${LIBJPEG_SOURCES_DIR}") - - include_directories( - ${LIBJPEG_SOURCES_DIR} - ) - - list(APPEND LIBJPEG_SOURCES - ${LIBJPEG_SOURCES_DIR}/jaricom.c - ${LIBJPEG_SOURCES_DIR}/jcapimin.c - ${LIBJPEG_SOURCES_DIR}/jcapistd.c - ${LIBJPEG_SOURCES_DIR}/jcarith.c - ${LIBJPEG_SOURCES_DIR}/jccoefct.c - ${LIBJPEG_SOURCES_DIR}/jccolor.c - ${LIBJPEG_SOURCES_DIR}/jcdctmgr.c - ${LIBJPEG_SOURCES_DIR}/jchuff.c - ${LIBJPEG_SOURCES_DIR}/jcinit.c - ${LIBJPEG_SOURCES_DIR}/jcmarker.c - ${LIBJPEG_SOURCES_DIR}/jcmaster.c - ${LIBJPEG_SOURCES_DIR}/jcomapi.c - ${LIBJPEG_SOURCES_DIR}/jcparam.c - ${LIBJPEG_SOURCES_DIR}/jcprepct.c - ${LIBJPEG_SOURCES_DIR}/jcsample.c - ${LIBJPEG_SOURCES_DIR}/jctrans.c - ${LIBJPEG_SOURCES_DIR}/jdapimin.c - ${LIBJPEG_SOURCES_DIR}/jdapistd.c - ${LIBJPEG_SOURCES_DIR}/jdarith.c - ${LIBJPEG_SOURCES_DIR}/jdatadst.c - ${LIBJPEG_SOURCES_DIR}/jdatasrc.c - ${LIBJPEG_SOURCES_DIR}/jdcoefct.c - ${LIBJPEG_SOURCES_DIR}/jdcolor.c - ${LIBJPEG_SOURCES_DIR}/jddctmgr.c - ${LIBJPEG_SOURCES_DIR}/jdhuff.c - ${LIBJPEG_SOURCES_DIR}/jdinput.c - ${LIBJPEG_SOURCES_DIR}/jcmainct.c - ${LIBJPEG_SOURCES_DIR}/jdmainct.c - ${LIBJPEG_SOURCES_DIR}/jdmarker.c - ${LIBJPEG_SOURCES_DIR}/jdmaster.c - ${LIBJPEG_SOURCES_DIR}/jdmerge.c - ${LIBJPEG_SOURCES_DIR}/jdpostct.c - ${LIBJPEG_SOURCES_DIR}/jdsample.c - ${LIBJPEG_SOURCES_DIR}/jdtrans.c - ${LIBJPEG_SOURCES_DIR}/jerror.c - ${LIBJPEG_SOURCES_DIR}/jfdctflt.c - ${LIBJPEG_SOURCES_DIR}/jfdctfst.c - ${LIBJPEG_SOURCES_DIR}/jfdctint.c - ${LIBJPEG_SOURCES_DIR}/jidctflt.c - ${LIBJPEG_SOURCES_DIR}/jidctfst.c - ${LIBJPEG_SOURCES_DIR}/jidctint.c - #${LIBJPEG_SOURCES_DIR}/jmemansi.c - #${LIBJPEG_SOURCES_DIR}/jmemdos.c - #${LIBJPEG_SOURCES_DIR}/jmemmac.c - ${LIBJPEG_SOURCES_DIR}/jmemmgr.c - #${LIBJPEG_SOURCES_DIR}/jmemname.c - ${LIBJPEG_SOURCES_DIR}/jmemnobs.c - ${LIBJPEG_SOURCES_DIR}/jquant1.c - ${LIBJPEG_SOURCES_DIR}/jquant2.c - ${LIBJPEG_SOURCES_DIR}/jutils.c - - # ${LIBJPEG_SOURCES_DIR}/rdbmp.c - # ${LIBJPEG_SOURCES_DIR}/rdcolmap.c - # ${LIBJPEG_SOURCES_DIR}/rdgif.c - # ${LIBJPEG_SOURCES_DIR}/rdppm.c - # ${LIBJPEG_SOURCES_DIR}/rdrle.c - # ${LIBJPEG_SOURCES_DIR}/rdswitch.c - # ${LIBJPEG_SOURCES_DIR}/rdtarga.c - # ${LIBJPEG_SOURCES_DIR}/transupp.c - # ${LIBJPEG_SOURCES_DIR}/wrbmp.c - # ${LIBJPEG_SOURCES_DIR}/wrgif.c - # ${LIBJPEG_SOURCES_DIR}/wrppm.c - # ${LIBJPEG_SOURCES_DIR}/wrrle.c - # ${LIBJPEG_SOURCES_DIR}/wrtarga.c - ) - - configure_file( - ${LIBJPEG_SOURCES_DIR}/jconfig.txt - ${LIBJPEG_SOURCES_DIR}/jconfig.h COPYONLY - ) - - source_group(ThirdParty\\libjpeg REGULAR_EXPRESSION ${LIBJPEG_SOURCES_DIR}/.*) - -else() - include(FindJPEG) - - if (NOT ${JPEG_FOUND}) - message(FATAL_ERROR "Unable to find libjpeg") - endif() - - include_directories(${JPEG_INCLUDE_DIR}) - link_libraries(${JPEG_LIBRARIES}) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibP11Configuration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibP11Configuration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibP11Configuration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibP11Configuration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11) - SET(LIBP11_SOURCES_DIR ${CMAKE_BINARY_DIR}/libp11-0.4.0) - SET(LIBP11_URL "http://orthanc.osimis.io/ThirdPartyDownloads/libp11-0.4.0.tar.gz") - SET(LIBP11_MD5 "00b3e41db5be840d822bda12f3ab2ca7") - - if (IS_DIRECTORY "${LIBP11_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() - - DownloadPackage(${LIBP11_MD5} ${LIBP11_URL} "${LIBP11_SOURCES_DIR}") - - # Apply the patches - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Patches/libp11-0.4.0.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure AND FirstRun) - message(FATAL_ERROR "Error while patching libp11") - endif() - - # This command MUST be after applying the patch - file(COPY - ${LIBP11_SOURCES_DIR}/src/engine.h - ${LIBP11_SOURCES_DIR}/src/libp11.h - DESTINATION ${AUTOGENERATED_DIR}/libp11) - - set(LIBP11_SOURCES - #${LIBP11_SOURCES_DIR}/src/eng_front.c - ${LIBP11_SOURCES_DIR}/src/eng_back.c - ${LIBP11_SOURCES_DIR}/src/eng_parse.c - ${LIBP11_SOURCES_DIR}/src/libpkcs11.c - ${LIBP11_SOURCES_DIR}/src/p11_attr.c - ${LIBP11_SOURCES_DIR}/src/p11_cert.c - ${LIBP11_SOURCES_DIR}/src/p11_ec.c - ${LIBP11_SOURCES_DIR}/src/p11_err.c - ${LIBP11_SOURCES_DIR}/src/p11_front.c - ${LIBP11_SOURCES_DIR}/src/p11_key.c - ${LIBP11_SOURCES_DIR}/src/p11_load.c - ${LIBP11_SOURCES_DIR}/src/p11_misc.c - ${LIBP11_SOURCES_DIR}/src/p11_rsa.c - ${LIBP11_SOURCES_DIR}/src/p11_slot.c - ) - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - list(APPEND LIBP11_SOURCES - ${LIBP11_SOURCES_DIR}/src/atfork.c - ) - endif() - - source_group(ThirdParty\\libp11 REGULAR_EXPRESSION ${LIBP11_SOURCES_DIR}/.*) - -else() - check_include_file_cxx(libp11.h HAVE_LIBP11_H) - if (NOT HAVE_LIBP11_H) - message(FATAL_ERROR "Please install the libp11-dev package") - endif() - - check_library_exists(p11 PKCS11_login "" HAVE_LIBP11_LIB) - if (NOT HAVE_LIBP11_LIB) - message(FATAL_ERROR "Please install the libp11-dev package") - endif() - - link_libraries(p11) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibPngConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibPngConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibPngConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LibPngConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG) - SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.6.36) - SET(LIBPNG_URL "http://orthanc.osimis.io/ThirdPartyDownloads/libpng-1.6.36.tar.gz") - SET(LIBPNG_MD5 "65afdeaa05f5ec14e31d9276143012e9") - - DownloadPackage(${LIBPNG_MD5} ${LIBPNG_URL} "${LIBPNG_SOURCES_DIR}") - - include_directories( - ${LIBPNG_SOURCES_DIR} - ) - - configure_file( - ${LIBPNG_SOURCES_DIR}/scripts/pnglibconf.h.prebuilt - ${LIBPNG_SOURCES_DIR}/pnglibconf.h - ) - - set(LIBPNG_SOURCES - #${LIBPNG_SOURCES_DIR}/example.c - ${LIBPNG_SOURCES_DIR}/png.c - ${LIBPNG_SOURCES_DIR}/pngerror.c - ${LIBPNG_SOURCES_DIR}/pngget.c - ${LIBPNG_SOURCES_DIR}/pngmem.c - ${LIBPNG_SOURCES_DIR}/pngpread.c - ${LIBPNG_SOURCES_DIR}/pngread.c - ${LIBPNG_SOURCES_DIR}/pngrio.c - ${LIBPNG_SOURCES_DIR}/pngrtran.c - ${LIBPNG_SOURCES_DIR}/pngrutil.c - ${LIBPNG_SOURCES_DIR}/pngset.c - #${LIBPNG_SOURCES_DIR}/pngtest.c - ${LIBPNG_SOURCES_DIR}/pngtrans.c - ${LIBPNG_SOURCES_DIR}/pngwio.c - ${LIBPNG_SOURCES_DIR}/pngwrite.c - ${LIBPNG_SOURCES_DIR}/pngwtran.c - ${LIBPNG_SOURCES_DIR}/pngwutil.c - ) - - add_definitions( - -DPNG_NO_CONFIG_H=1 - -DPNG_NO_CONSOLE_IO=1 - -DPNG_NO_STDIO=1 - # The following declaration avoids "__declspec(dllexport)" in - # libpng to prevent publicly exposing its symbols by the DLLs - -DPNG_IMPEXP= - ) - - source_group(ThirdParty\\libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*) - -else() - include(FindPNG) - - if (NOT ${PNG_FOUND}) - message(FATAL_ERROR "Unable to find libpng") - endif() - - include_directories(${PNG_INCLUDE_DIRS}) - link_libraries(${PNG_LIBRARIES}) - add_definitions(${PNG_DEFINITIONS}) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LuaConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LuaConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LuaConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/LuaConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_LUA) - SET(LUA_SOURCES_DIR ${CMAKE_BINARY_DIR}/lua-5.3.5) - SET(LUA_MD5 "4f4b4f323fd3514a68e0ab3da8ce3455") - SET(LUA_URL "http://orthanc.osimis.io/ThirdPartyDownloads/lua-5.3.5.tar.gz") - - DownloadPackage(${LUA_MD5} ${LUA_URL} "${LUA_SOURCES_DIR}") - - if (ENABLE_LUA_MODULES) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - # Enable loading of shared libraries (for UNIX-like) - add_definitions(-DLUA_USE_DLOPEN=1) - - # Publish the functions of the Lua engine (that are built within - # the Orthanc binary) as global symbols, so that the external - # shared libraries can call them - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--export-dynamic") - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") - add_definitions(-DLUA_USE_LINUX=1) - elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - add_definitions( - -DLUA_USE_LINUX=1 - -DLUA_USE_READLINE=1 - ) - elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - add_definitions(-DLUA_USE_POSIX=1) - endif() - - elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - add_definitions( - -DLUA_DL_DLL=1 # Enable loading of shared libraries (for Microsoft Windows) - ) - - elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - add_definitions( - -DLUA_USE_MACOSX=1 - -DLUA_DL_DYLD=1 # Enable loading of shared libraries (for Apple OS X) - ) - - else() - message(FATAL_ERROR "Support your platform here") - endif() - endif() - - add_definitions( - -DLUA_COMPAT_5_2=1 - ) - - include_directories( - ${LUA_SOURCES_DIR}/src - ) - - set(LUA_SOURCES - # Don't compile the Lua command-line - #${LUA_SOURCES_DIR}/src/lua.c - #${LUA_SOURCES_DIR}/src/luac.c - - # Core Lua - ${LUA_SOURCES_DIR}/src/lapi.c - ${LUA_SOURCES_DIR}/src/lcode.c - ${LUA_SOURCES_DIR}/src/lctype.c - ${LUA_SOURCES_DIR}/src/ldebug.c - ${LUA_SOURCES_DIR}/src/ldo.c - ${LUA_SOURCES_DIR}/src/ldump.c - ${LUA_SOURCES_DIR}/src/lfunc.c - ${LUA_SOURCES_DIR}/src/lgc.c - ${LUA_SOURCES_DIR}/src/llex.c - ${LUA_SOURCES_DIR}/src/lmem.c - ${LUA_SOURCES_DIR}/src/lobject.c - ${LUA_SOURCES_DIR}/src/lopcodes.c - ${LUA_SOURCES_DIR}/src/lparser.c - ${LUA_SOURCES_DIR}/src/lstate.c - ${LUA_SOURCES_DIR}/src/lstring.c - ${LUA_SOURCES_DIR}/src/ltable.c - ${LUA_SOURCES_DIR}/src/ltm.c - ${LUA_SOURCES_DIR}/src/lundump.c - ${LUA_SOURCES_DIR}/src/lvm.c - ${LUA_SOURCES_DIR}/src/lzio.c - - # Base Lua modules - ${LUA_SOURCES_DIR}/src/lauxlib.c - ${LUA_SOURCES_DIR}/src/lbaselib.c - ${LUA_SOURCES_DIR}/src/lbitlib.c - ${LUA_SOURCES_DIR}/src/lcorolib.c - ${LUA_SOURCES_DIR}/src/ldblib.c - ${LUA_SOURCES_DIR}/src/liolib.c - ${LUA_SOURCES_DIR}/src/lmathlib.c - ${LUA_SOURCES_DIR}/src/loadlib.c - ${LUA_SOURCES_DIR}/src/loslib.c - ${LUA_SOURCES_DIR}/src/lstrlib.c - ${LUA_SOURCES_DIR}/src/ltablib.c - ${LUA_SOURCES_DIR}/src/lutf8lib.c - - ${LUA_SOURCES_DIR}/src/linit.c - ) - - source_group(ThirdParty\\Lua REGULAR_EXPRESSION ${LUA_SOURCES_DIR}/.*) - -elseif (CMAKE_CROSSCOMPILING AND - "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") - - set(LUA_VERSIONS 5.3 5.2 5.1) - - unset(LUA_VERSION) - foreach(version IN ITEMS ${LUA_VERSIONS}) - CHECK_INCLUDE_FILE(lua${version}/lua.h HAVE_LUA${version}_H) - if (HAVE_LUA${version}_H) - set(LUA_VERSION ${version}) - break() - endif() - endforeach() - - if (NOT LUA_VERSION) - message(FATAL_ERROR "Please install the liblua-dev package") - endif() - - CHECK_LIBRARY_EXISTS(lua${LUA_VERSION} "lua_call" "${LUA_LIB_DIR}" HAVE_LUA_LIB) - if (NOT HAVE_LUA_LIB) - message(FATAL_ERROR "Please install the liblua package") - endif() - - include_directories(${CROSSTOOL_NG_IMAGE}/usr/include/lua${LUA_VERSION}) - link_libraries(lua${LUA_VERSION}) - -else() - include(FindLua) - - if (NOT LUA_FOUND) - message(FATAL_ERROR "Please install the liblua-dev package") - endif() - - include_directories(${LUA_INCLUDE_DIR}) - link_libraries(${LUA_LIBRARIES}) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/MongooseConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/MongooseConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/MongooseConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/MongooseConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_MONGOOSE) - SET(MONGOOSE_SOURCES_DIR ${CMAKE_BINARY_DIR}/mongoose) - - if (IS_DIRECTORY "${MONGOOSE_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() - - if (0) - # Use Mongoose 3.1 - DownloadPackage( - "e718fc287b4eb1bd523be3fa00942bb0" - "http://orthanc.osimis.io/ThirdPartyDownloads/mongoose-3.1.tgz" - "${MONGOOSE_SOURCES_DIR}") - - add_definitions(-DMONGOOSE_USE_CALLBACKS=0) - set(MONGOOSE_PATCH ${ORTHANC_ROOT}/Resources/Patches/mongoose-3.1-patch.diff) - - else() - # Use Mongoose 3.8 - DownloadPackage( - "7e3296295072792cdc3c633f9404e0c3" - "http://orthanc.osimis.io/ThirdPartyDownloads/mongoose-3.8.tgz" - "${MONGOOSE_SOURCES_DIR}") - - add_definitions(-DMONGOOSE_USE_CALLBACKS=1) - set(MONGOOSE_PATCH ${ORTHANC_ROOT}/Resources/Patches/mongoose-3.8-patch.diff) - endif() - - # Patch mongoose - execute_process( - COMMAND ${PATCH_EXECUTABLE} -N mongoose.c - INPUT_FILE ${MONGOOSE_PATCH} - WORKING_DIRECTORY ${MONGOOSE_SOURCES_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure AND FirstRun) - message(FATAL_ERROR "Error while patching a file") - endif() - - include_directories( - ${MONGOOSE_SOURCES_DIR} - ) - - set(MONGOOSE_SOURCES - ${MONGOOSE_SOURCES_DIR}/mongoose.c - ) - - - if (ENABLE_SSL) - add_definitions( - -DNO_SSL_DL=1 - ) - if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD") - link_libraries(dl) - endif() - - else() - add_definitions( - -DNO_SSL=1 # Remove SSL support from mongoose - ) - endif() - - - if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if (CMAKE_COMPILER_IS_GNUCXX) - # This is a patch for MinGW64 - add_definitions(-D_TIMESPEC_DEFINED=1) - endif() - endif() - - source_group(ThirdParty\\Mongoose REGULAR_EXPRESSION ${MONGOOSE_SOURCES_DIR}/.*) - -else() - CHECK_INCLUDE_FILE_CXX(mongoose.h HAVE_MONGOOSE_H) - if (NOT HAVE_MONGOOSE_H) - message(FATAL_ERROR "Please install the mongoose-devel package") - endif() - - CHECK_LIBRARY_EXISTS(mongoose mg_start "" HAVE_MONGOOSE_LIB) - if (NOT HAVE_MONGOOSE_LIB) - message(FATAL_ERROR "Please install the mongoose-devel package") - endif() - - if (SYSTEM_MONGOOSE_USE_CALLBACKS) - add_definitions(-DMONGOOSE_USE_CALLBACKS=1) - else() - add_definitions(-DMONGOOSE_USE_CALLBACKS=0) - endif() - - link_libraries(mongoose) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL) - if (OPENSSL_STATIC_VERSION STREQUAL "1.0.2") - include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfigurationStatic-1.0.2.cmake) - elseif (OPENSSL_STATIC_VERSION STREQUAL "1.1.1") - include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfigurationStatic-1.1.1.cmake) - else() - message(FATAL_ERROR "Unsupported version of OpenSSL: ${OPENSSL_STATIC_VERSION}") - endif() - - source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*) - -elseif (CMAKE_CROSSCOMPILING AND - "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") - - CHECK_INCLUDE_FILE_CXX(openssl/opensslv.h HAVE_OPENSSL_H) - if (NOT HAVE_OPENSSL_H) - message(FATAL_ERROR "Please install the libopenssl-dev package") - endif() - - CHECK_LIBRARY_EXISTS(crypto "OPENSSL_init" "" HAVE_OPENSSL_CRYPTO_LIB) - if (NOT HAVE_OPENSSL_CRYPTO_LIB) - message(FATAL_ERROR "Please install the libopenssl package") - endif() - - CHECK_LIBRARY_EXISTS(ssl "SSL_library_init" "" HAVE_OPENSSL_SSL_LIB) - if (NOT HAVE_OPENSSL_SSL_LIB) - message(FATAL_ERROR "Please install the libopenssl package") - endif() - - link_libraries(crypto ssl) - -else() - include(FindOpenSSL) - - if (NOT ${OPENSSL_FOUND}) - message(FATAL_ERROR "Unable to find OpenSSL") - endif() - - include_directories(${OPENSSL_INCLUDE_DIR}) - link_libraries(${OPENSSL_LIBRARIES}) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.0.2.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.0.2.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.0.2.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.0.2.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,332 +0,0 @@ -SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2p) -SET(OPENSSL_URL "http://orthanc.osimis.io/ThirdPartyDownloads/openssl-1.0.2p.tar.gz") -SET(OPENSSL_MD5 "ac5eb30bf5798aa14b1ae6d0e7da58df") - -if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}") - set(FirstRun OFF) -else() - set(FirstRun ON) -endif() - -DownloadPackage(${OPENSSL_MD5} ${OPENSSL_URL} "${OPENSSL_SOURCES_DIR}") - -if (FirstRun) - file(MAKE_DIRECTORY ${OPENSSL_SOURCES_DIR}/include/openssl) - - foreach(header - ${OPENSSL_SOURCES_DIR}/crypto/aes/aes.h - ${OPENSSL_SOURCES_DIR}/crypto/asn1/asn1.h - ${OPENSSL_SOURCES_DIR}/crypto/asn1/asn1_mac.h - ${OPENSSL_SOURCES_DIR}/crypto/asn1/asn1t.h - ${OPENSSL_SOURCES_DIR}/crypto/bf/blowfish.h - ${OPENSSL_SOURCES_DIR}/crypto/bio/bio.h - ${OPENSSL_SOURCES_DIR}/crypto/bn/bn.h - ${OPENSSL_SOURCES_DIR}/crypto/buffer/buffer.h - ${OPENSSL_SOURCES_DIR}/crypto/camellia/camellia.h - ${OPENSSL_SOURCES_DIR}/crypto/cast/cast.h - ${OPENSSL_SOURCES_DIR}/crypto/cmac/cmac.h - ${OPENSSL_SOURCES_DIR}/crypto/cms/cms.h - ${OPENSSL_SOURCES_DIR}/crypto/comp/comp.h - ${OPENSSL_SOURCES_DIR}/crypto/conf/conf.h - ${OPENSSL_SOURCES_DIR}/crypto/conf/conf_api.h - ${OPENSSL_SOURCES_DIR}/crypto/crypto.h - ${OPENSSL_SOURCES_DIR}/crypto/des/des.h - ${OPENSSL_SOURCES_DIR}/crypto/des/des_old.h - ${OPENSSL_SOURCES_DIR}/crypto/dh/dh.h - ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsa.h - ${OPENSSL_SOURCES_DIR}/crypto/dso/dso.h - ${OPENSSL_SOURCES_DIR}/crypto/ebcdic.h - ${OPENSSL_SOURCES_DIR}/crypto/ec/ec.h - ${OPENSSL_SOURCES_DIR}/crypto/ecdh/ecdh.h - ${OPENSSL_SOURCES_DIR}/crypto/ecdsa/ecdsa.h - ${OPENSSL_SOURCES_DIR}/crypto/engine/engine.h - ${OPENSSL_SOURCES_DIR}/crypto/err/err.h - ${OPENSSL_SOURCES_DIR}/crypto/evp/evp.h - ${OPENSSL_SOURCES_DIR}/crypto/hmac/hmac.h - ${OPENSSL_SOURCES_DIR}/crypto/idea/idea.h - ${OPENSSL_SOURCES_DIR}/crypto/jpake/jpake.h - ${OPENSSL_SOURCES_DIR}/crypto/krb5/krb5_asn.h - ${OPENSSL_SOURCES_DIR}/crypto/lhash/lhash.h - ${OPENSSL_SOURCES_DIR}/crypto/md2/md2.h - ${OPENSSL_SOURCES_DIR}/crypto/md4/md4.h - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5.h - ${OPENSSL_SOURCES_DIR}/crypto/mdc2/mdc2.h - ${OPENSSL_SOURCES_DIR}/crypto/modes/modes.h - ${OPENSSL_SOURCES_DIR}/crypto/objects/obj_mac.h - ${OPENSSL_SOURCES_DIR}/crypto/objects/objects.h - ${OPENSSL_SOURCES_DIR}/crypto/ocsp/ocsp.h - ${OPENSSL_SOURCES_DIR}/crypto/opensslconf.h - ${OPENSSL_SOURCES_DIR}/crypto/opensslv.h - ${OPENSSL_SOURCES_DIR}/crypto/ossl_typ.h - ${OPENSSL_SOURCES_DIR}/crypto/pem/pem.h - ${OPENSSL_SOURCES_DIR}/crypto/pem/pem2.h - ${OPENSSL_SOURCES_DIR}/crypto/pkcs12/pkcs12.h - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/pkcs7.h - ${OPENSSL_SOURCES_DIR}/crypto/pqueue/pqueue.h - ${OPENSSL_SOURCES_DIR}/crypto/rand/rand.h - ${OPENSSL_SOURCES_DIR}/crypto/rc2/rc2.h - ${OPENSSL_SOURCES_DIR}/crypto/rc4/rc4.h - ${OPENSSL_SOURCES_DIR}/crypto/rc5/rc5.h - ${OPENSSL_SOURCES_DIR}/crypto/ripemd/ripemd.h - ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa.h - ${OPENSSL_SOURCES_DIR}/crypto/seed/seed.h - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha.h - ${OPENSSL_SOURCES_DIR}/crypto/srp/srp.h - ${OPENSSL_SOURCES_DIR}/crypto/stack/safestack.h - ${OPENSSL_SOURCES_DIR}/crypto/stack/stack.h - ${OPENSSL_SOURCES_DIR}/crypto/store/store.h - ${OPENSSL_SOURCES_DIR}/crypto/symhacks.h - ${OPENSSL_SOURCES_DIR}/crypto/ts/ts.h - ${OPENSSL_SOURCES_DIR}/crypto/txt_db/txt_db.h - ${OPENSSL_SOURCES_DIR}/crypto/ui/ui.h - ${OPENSSL_SOURCES_DIR}/crypto/ui/ui_compat.h - ${OPENSSL_SOURCES_DIR}/crypto/whrlpool/whrlpool.h - ${OPENSSL_SOURCES_DIR}/crypto/x509/x509.h - ${OPENSSL_SOURCES_DIR}/crypto/x509/x509_vfy.h - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/x509v3.h - ${OPENSSL_SOURCES_DIR}/e_os2.h - ${OPENSSL_SOURCES_DIR}/ssl/dtls1.h - ${OPENSSL_SOURCES_DIR}/ssl/kssl.h - ${OPENSSL_SOURCES_DIR}/ssl/srtp.h - ${OPENSSL_SOURCES_DIR}/ssl/ssl.h - ${OPENSSL_SOURCES_DIR}/ssl/ssl2.h - ${OPENSSL_SOURCES_DIR}/ssl/ssl23.h - ${OPENSSL_SOURCES_DIR}/ssl/ssl3.h - ${OPENSSL_SOURCES_DIR}/ssl/tls1.h - ) - file(COPY ${header} DESTINATION ${OPENSSL_SOURCES_DIR}/include/openssl) - endforeach() - - file(RENAME - ${OPENSSL_SOURCES_DIR}/include/openssl/e_os2.h - ${OPENSSL_SOURCES_DIR}/include/openssl/e_os2_source.h) - - # The following patch of "e_os2.h" prevents from building OpenSSL - # as a DLL under Windows. Otherwise, symbols have inconsistent - # linkage if ${OPENSSL_SOURCES} is used to create a DLL (notably - # if building an Orthanc plugin such as MySQL). - file(WRITE ${OPENSSL_SOURCES_DIR}/include/openssl/e_os2.h " -#include \"e_os2_source.h\" -#if defined(_WIN32) -# undef OPENSSL_EXPORT -# undef OPENSSL_IMPORT -# undef OPENSSL_EXTERN -# undef OPENSSL_GLOBAL -# define OPENSSL_EXPORT -# define OPENSSL_IMPORT -# define OPENSSL_EXTERN extern -# define OPENSSL_GLOBAL -#endif -") -endif() - -add_definitions( - -DOPENSSL_THREADS - -DOPENSSL_IA32_SSE2 - -DOPENSSL_NO_ASM - -DOPENSSL_NO_DYNAMIC_ENGINE - -DNO_WINDOWS_BRAINDEATH - - -DOPENSSL_NO_BF - -DOPENSSL_NO_CAMELLIA - -DOPENSSL_NO_CAST - -DOPENSSL_NO_EC_NISTP_64_GCC_128 - -DOPENSSL_NO_GMP - -DOPENSSL_NO_GOST - -DOPENSSL_NO_HW - -DOPENSSL_NO_JPAKE - -DOPENSSL_NO_IDEA - -DOPENSSL_NO_KRB5 - -DOPENSSL_NO_MD2 - -DOPENSSL_NO_MDC2 - #-DOPENSSL_NO_MD4 # MD4 is necessary for MariaDB/MySQL client - -DOPENSSL_NO_RC2 - -DOPENSSL_NO_RC4 - -DOPENSSL_NO_RC5 - -DOPENSSL_NO_RFC3779 - -DOPENSSL_NO_SCTP - -DOPENSSL_NO_STORE - -DOPENSSL_NO_SEED - -DOPENSSL_NO_WHIRLPOOL - -DOPENSSL_NO_RIPEMD - ) - -include_directories( - ${OPENSSL_SOURCES_DIR} - ${OPENSSL_SOURCES_DIR}/crypto - ${OPENSSL_SOURCES_DIR}/crypto/asn1 - ${OPENSSL_SOURCES_DIR}/crypto/modes - ${OPENSSL_SOURCES_DIR}/crypto/evp - ${OPENSSL_SOURCES_DIR}/include - ) - -set(OPENSSL_SOURCES_SUBDIRS - ${OPENSSL_SOURCES_DIR}/crypto - ${OPENSSL_SOURCES_DIR}/crypto/aes - ${OPENSSL_SOURCES_DIR}/crypto/asn1 - ${OPENSSL_SOURCES_DIR}/crypto/bio - ${OPENSSL_SOURCES_DIR}/crypto/bn - ${OPENSSL_SOURCES_DIR}/crypto/buffer - ${OPENSSL_SOURCES_DIR}/crypto/cmac - ${OPENSSL_SOURCES_DIR}/crypto/cms - ${OPENSSL_SOURCES_DIR}/crypto/comp - ${OPENSSL_SOURCES_DIR}/crypto/conf - ${OPENSSL_SOURCES_DIR}/crypto/des - ${OPENSSL_SOURCES_DIR}/crypto/dh - ${OPENSSL_SOURCES_DIR}/crypto/dsa - ${OPENSSL_SOURCES_DIR}/crypto/dso - ${OPENSSL_SOURCES_DIR}/crypto/engine - ${OPENSSL_SOURCES_DIR}/crypto/err - ${OPENSSL_SOURCES_DIR}/crypto/evp - ${OPENSSL_SOURCES_DIR}/crypto/hmac - ${OPENSSL_SOURCES_DIR}/crypto/lhash - ${OPENSSL_SOURCES_DIR}/crypto/md4 - ${OPENSSL_SOURCES_DIR}/crypto/md5 - ${OPENSSL_SOURCES_DIR}/crypto/modes - ${OPENSSL_SOURCES_DIR}/crypto/objects - ${OPENSSL_SOURCES_DIR}/crypto/ocsp - ${OPENSSL_SOURCES_DIR}/crypto/pem - ${OPENSSL_SOURCES_DIR}/crypto/pkcs12 - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7 - ${OPENSSL_SOURCES_DIR}/crypto/pqueue - ${OPENSSL_SOURCES_DIR}/crypto/rand - ${OPENSSL_SOURCES_DIR}/crypto/rsa - ${OPENSSL_SOURCES_DIR}/crypto/sha - ${OPENSSL_SOURCES_DIR}/crypto/srp - ${OPENSSL_SOURCES_DIR}/crypto/stack - ${OPENSSL_SOURCES_DIR}/crypto/ts - ${OPENSSL_SOURCES_DIR}/crypto/txt_db - ${OPENSSL_SOURCES_DIR}/crypto/ui - ${OPENSSL_SOURCES_DIR}/crypto/x509 - ${OPENSSL_SOURCES_DIR}/crypto/x509v3 - ${OPENSSL_SOURCES_DIR}/ssl - ) - -if (ENABLE_OPENSSL_ENGINES) - list(APPEND OPENSSL_SOURCES_SUBDIRS - ${OPENSSL_SOURCES_DIR}/engines - ) -endif() - -list(APPEND OPENSSL_SOURCES_SUBDIRS - # EC, ECDH and ECDSA are necessary for PKCS11, and for contacting - # HTTPS servers that use TLS certificate encrypted with ECDSA - # (check the output of a recent version of the "sslscan" - # command). Until Orthanc <= 1.4.1, these features were only - # enabled if ENABLE_PKCS11 support was set to "ON". - # https://groups.google.com/d/msg/orthanc-users/2l-bhYIMEWg/oMmK33bYBgAJ - ${OPENSSL_SOURCES_DIR}/crypto/ec - ${OPENSSL_SOURCES_DIR}/crypto/ecdh - ${OPENSSL_SOURCES_DIR}/crypto/ecdsa - ) - -foreach(d ${OPENSSL_SOURCES_SUBDIRS}) - AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES) -endforeach() - -list(REMOVE_ITEM OPENSSL_SOURCES - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_unix.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_vms.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c - ${OPENSSL_SOURCES_DIR}/crypto/armcap.c - ${OPENSSL_SOURCES_DIR}/crypto/bf/bfs.cpp - ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_rtcp.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/exp.c - ${OPENSSL_SOURCES_DIR}/crypto/conf/cnf_save.c - ${OPENSSL_SOURCES_DIR}/crypto/conf/test.c - ${OPENSSL_SOURCES_DIR}/crypto/des/des.c - ${OPENSSL_SOURCES_DIR}/crypto/des/des3s.cpp - ${OPENSSL_SOURCES_DIR}/crypto/des/des_opts.c - ${OPENSSL_SOURCES_DIR}/crypto/des/dess.cpp - ${OPENSSL_SOURCES_DIR}/crypto/des/read_pwd.c - ${OPENSSL_SOURCES_DIR}/crypto/des/speed.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/e_dsa.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/m_ripemd.c - ${OPENSSL_SOURCES_DIR}/crypto/lhash/lh_test.c - ${OPENSSL_SOURCES_DIR}/crypto/md4/md4.c - ${OPENSSL_SOURCES_DIR}/crypto/md4/md4s.cpp - ${OPENSSL_SOURCES_DIR}/crypto/md4/md4test.c - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5s.cpp - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/bio_ber.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/pk7_enc.c - ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c - ${OPENSSL_SOURCES_DIR}/crypto/rand/randtest.c - ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c - ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/tabtest.c - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3conf.c - ${OPENSSL_SOURCES_DIR}/ssl/ssl_task.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_nyi.c - ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c - ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_dgram.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/bntest.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/expspeed.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/exptest.c - ${OPENSSL_SOURCES_DIR}/crypto/engine/enginetest.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_test.c - ${OPENSSL_SOURCES_DIR}/crypto/hmac/hmactest.c - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5.c - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5test.c - ${OPENSSL_SOURCES_DIR}/crypto/o_dir_test.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/dec.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/enc.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/sign.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/verify.c - ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa_test.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1t.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1test.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha256t.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha512t.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/shatest.c - ${OPENSSL_SOURCES_DIR}/crypto/srp/srptest.c - - ${OPENSSL_SOURCES_DIR}/crypto/bn/divtest.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/bnspeed.c - ${OPENSSL_SOURCES_DIR}/crypto/des/destest.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/p192.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/p512.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/p1024.c - ${OPENSSL_SOURCES_DIR}/crypto/des/rpw.c - ${OPENSSL_SOURCES_DIR}/ssl/ssltest.c - ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsagen.c - ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsatest.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/dhtest.c - ${OPENSSL_SOURCES_DIR}/crypto/pqueue/pq_test.c - ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c - - ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_extra_test.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/verify_extra_test.c - ${OPENSSL_SOURCES_DIR}/crypto/x509/verify_extra_test.c - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3prin.c - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3nametest.c - ${OPENSSL_SOURCES_DIR}/crypto/constant_time_test.c - - ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c - ${OPENSSL_SOURCES_DIR}/ssl/fatalerrtest.c - ${OPENSSL_SOURCES_DIR}/ssl/dtlstest.c - ${OPENSSL_SOURCES_DIR}/ssl/bad_dtls_test.c - ${OPENSSL_SOURCES_DIR}/ssl/clienthellotest.c - ${OPENSSL_SOURCES_DIR}/ssl/sslv2conftest.c - - ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256.c - ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c - ${OPENSSL_SOURCES_DIR}/crypto/ec/ectest.c - ${OPENSSL_SOURCES_DIR}/crypto/ecdh/ecdhtest.c - ${OPENSSL_SOURCES_DIR}/crypto/ecdsa/ecdsatest.c - ) - - -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") - set_source_files_properties( - ${OPENSSL_SOURCES} - PROPERTIES COMPILE_DEFINITIONS - "OPENSSL_SYSNAME_WIN32;SO_WIN32;WIN32_LEAN_AND_MEAN;L_ENDIAN") - - if (ENABLE_OPENSSL_ENGINES) - link_libraries(crypt32) - endif() -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OpenSslConfigurationStatic-1.1.1.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,258 +0,0 @@ -SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.1.1g) -SET(OPENSSL_URL "http://orthanc.osimis.io/ThirdPartyDownloads/openssl-1.1.1g.tar.gz") -SET(OPENSSL_MD5 "76766e98997660138cdaf13a187bd234") - -if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}") - set(FirstRun OFF) -else() - set(FirstRun ON) -endif() - -DownloadPackage(${OPENSSL_MD5} ${OPENSSL_URL} "${OPENSSL_SOURCES_DIR}") - -if (FirstRun) - file(WRITE ${OPENSSL_SOURCES_DIR}/crypto/buildinf.h " -#define DATE \"\" -#define PLATFORM \"\" -#define compiler_flags \"\" -") - file(WRITE ${OPENSSL_SOURCES_DIR}/crypto/bn_conf.h "") - file(WRITE ${OPENSSL_SOURCES_DIR}/crypto/dso_conf.h "") - - configure_file( - ${ORTHANC_ROOT}/Resources/Patches/openssl-1.1.1-conf.h.in - ${OPENSSL_SOURCES_DIR}/include/openssl/opensslconf.h - ) - - # Apply the patches - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/openssl-1.1.1g.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while patching a file") - endif() -else() - message("The patches for OpenSSL have already been applied") -endif() - -add_definitions( - -DOPENSSL_THREADS - -DOPENSSL_IA32_SSE2 - -DOPENSSL_NO_ASM - -DOPENSSL_NO_DYNAMIC_ENGINE - -DOPENSSL_NO_DEVCRYPTOENG - - -DOPENSSL_NO_BF - -DOPENSSL_NO_CAMELLIA - -DOPENSSL_NO_CAST - -DOPENSSL_NO_EC_NISTP_64_GCC_128 - -DOPENSSL_NO_GMP - -DOPENSSL_NO_GOST - -DOPENSSL_NO_HW - -DOPENSSL_NO_JPAKE - -DOPENSSL_NO_IDEA - -DOPENSSL_NO_KRB5 - -DOPENSSL_NO_MD2 - -DOPENSSL_NO_MDC2 - #-DOPENSSL_NO_MD4 # MD4 is necessary for MariaDB/MySQL client - -DOPENSSL_NO_RC2 - -DOPENSSL_NO_RC4 - -DOPENSSL_NO_RC5 - -DOPENSSL_NO_RFC3779 - -DOPENSSL_NO_SCTP - -DOPENSSL_NO_STORE - -DOPENSSL_NO_SEED - -DOPENSSL_NO_WHIRLPOOL - -DOPENSSL_NO_RIPEMD - -DOPENSSL_NO_AFALGENG - - -DOPENSSLDIR="/usr/local/ssl" - ) - - -include_directories( - ${OPENSSL_SOURCES_DIR} - ${OPENSSL_SOURCES_DIR}/crypto - ${OPENSSL_SOURCES_DIR}/crypto/asn1 - ${OPENSSL_SOURCES_DIR}/crypto/ec/curve448 - ${OPENSSL_SOURCES_DIR}/crypto/ec/curve448/arch_32 - ${OPENSSL_SOURCES_DIR}/crypto/evp - ${OPENSSL_SOURCES_DIR}/crypto/include - ${OPENSSL_SOURCES_DIR}/crypto/modes - ${OPENSSL_SOURCES_DIR}/include - ) - - -set(OPENSSL_SOURCES_SUBDIRS - ${OPENSSL_SOURCES_DIR}/crypto - ${OPENSSL_SOURCES_DIR}/crypto/aes - ${OPENSSL_SOURCES_DIR}/crypto/aria - ${OPENSSL_SOURCES_DIR}/crypto/asn1 - ${OPENSSL_SOURCES_DIR}/crypto/async - ${OPENSSL_SOURCES_DIR}/crypto/async/arch - ${OPENSSL_SOURCES_DIR}/crypto/bio - ${OPENSSL_SOURCES_DIR}/crypto/blake2 - ${OPENSSL_SOURCES_DIR}/crypto/bn - ${OPENSSL_SOURCES_DIR}/crypto/buffer - ${OPENSSL_SOURCES_DIR}/crypto/chacha - ${OPENSSL_SOURCES_DIR}/crypto/cmac - ${OPENSSL_SOURCES_DIR}/crypto/cms - ${OPENSSL_SOURCES_DIR}/crypto/comp - ${OPENSSL_SOURCES_DIR}/crypto/conf - ${OPENSSL_SOURCES_DIR}/crypto/ct - ${OPENSSL_SOURCES_DIR}/crypto/des - ${OPENSSL_SOURCES_DIR}/crypto/dh - ${OPENSSL_SOURCES_DIR}/crypto/dsa - ${OPENSSL_SOURCES_DIR}/crypto/dso - ${OPENSSL_SOURCES_DIR}/crypto/ec - ${OPENSSL_SOURCES_DIR}/crypto/ec/curve448 - ${OPENSSL_SOURCES_DIR}/crypto/ec/curve448/arch_32 - ${OPENSSL_SOURCES_DIR}/crypto/err - ${OPENSSL_SOURCES_DIR}/crypto/evp - ${OPENSSL_SOURCES_DIR}/crypto/hmac - ${OPENSSL_SOURCES_DIR}/crypto/kdf - ${OPENSSL_SOURCES_DIR}/crypto/lhash - ${OPENSSL_SOURCES_DIR}/crypto/md4 - ${OPENSSL_SOURCES_DIR}/crypto/md5 - ${OPENSSL_SOURCES_DIR}/crypto/modes - ${OPENSSL_SOURCES_DIR}/crypto/objects - ${OPENSSL_SOURCES_DIR}/crypto/ocsp - ${OPENSSL_SOURCES_DIR}/crypto/pem - ${OPENSSL_SOURCES_DIR}/crypto/pkcs12 - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7 - ${OPENSSL_SOURCES_DIR}/crypto/poly1305 - ${OPENSSL_SOURCES_DIR}/crypto/pqueue - ${OPENSSL_SOURCES_DIR}/crypto/rand - ${OPENSSL_SOURCES_DIR}/crypto/ripemd - ${OPENSSL_SOURCES_DIR}/crypto/rsa - ${OPENSSL_SOURCES_DIR}/crypto/sha - ${OPENSSL_SOURCES_DIR}/crypto/siphash - ${OPENSSL_SOURCES_DIR}/crypto/sm2 - ${OPENSSL_SOURCES_DIR}/crypto/sm3 - ${OPENSSL_SOURCES_DIR}/crypto/sm4 - ${OPENSSL_SOURCES_DIR}/crypto/srp - ${OPENSSL_SOURCES_DIR}/crypto/stack - ${OPENSSL_SOURCES_DIR}/crypto/store - ${OPENSSL_SOURCES_DIR}/crypto/ts - ${OPENSSL_SOURCES_DIR}/crypto/txt_db - ${OPENSSL_SOURCES_DIR}/crypto/ui - ${OPENSSL_SOURCES_DIR}/crypto/x509 - ${OPENSSL_SOURCES_DIR}/crypto/x509v3 - ${OPENSSL_SOURCES_DIR}/ssl - ${OPENSSL_SOURCES_DIR}/ssl/record - ${OPENSSL_SOURCES_DIR}/ssl/statem - ) - -if (ENABLE_OPENSSL_ENGINES) - add_definitions( - #-DENGINESDIR="/usr/local/lib/engines-1.1" # On GNU/Linux - -DENGINESDIR="." - ) - - list(APPEND OPENSSL_SOURCES_SUBDIRS - ${OPENSSL_SOURCES_DIR}/engines - ${OPENSSL_SOURCES_DIR}/crypto/engine - ) -else() - add_definitions(-DOPENSSL_NO_ENGINE) -endif() - -list(APPEND OPENSSL_SOURCES_SUBDIRS - # EC, ECDH and ECDSA are necessary for PKCS11, and for contacting - # HTTPS servers that use TLS certificate encrypted with ECDSA - # (check the output of a recent version of the "sslscan" - # command). Until Orthanc <= 1.4.1, these features were only - # enabled if ENABLE_PKCS11 support was set to "ON". - # https://groups.google.com/d/msg/orthanc-users/2l-bhYIMEWg/oMmK33bYBgAJ - ${OPENSSL_SOURCES_DIR}/crypto/ec - ${OPENSSL_SOURCES_DIR}/crypto/ecdh - ${OPENSSL_SOURCES_DIR}/crypto/ecdsa - ) - -foreach(d ${OPENSSL_SOURCES_SUBDIRS}) - AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES) -endforeach() - -list(REMOVE_ITEM OPENSSL_SOURCES - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_nyi.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_unix.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_vms.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c - ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c - ${OPENSSL_SOURCES_DIR}/crypto/armcap.c - ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_dgram.c - ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c - ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256.c - ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c - ${OPENSSL_SOURCES_DIR}/crypto/engine/eng_devcrypto.c - ${OPENSSL_SOURCES_DIR}/crypto/poly1305/poly1305_base2_44.c # Cannot be compiled with MinGW - ${OPENSSL_SOURCES_DIR}/crypto/poly1305/poly1305_ieee754.c # Cannot be compiled with MinGW - ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c - ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c - ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c - ${OPENSSL_SOURCES_DIR}/engines/e_afalg.c # Cannot be compiled with MinGW - ) - -# Check out "${OPENSSL_SOURCES_DIR}/Configurations/README": "This is -# default if no option is specified, it works on any supported -# system." It is mandatory to define it as a macro, as it is used by -# all the source files that include OpenSSL (e.g. "Core/Toolbox.cpp" -# or curl) -add_definitions(-DTHIRTY_TWO_BIT) - - -if (NOT CMAKE_COMPILER_IS_GNUCXX OR - "${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" OR - "${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - # Disable the use of a gcc extension, that is neither available on - # MinGW, nor on LSB - add_definitions( - -DOPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE - ) -endif() - - -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") - set(OPENSSL_DEFINITIONS - "${OPENSSL_DEFINITIONS};OPENSSL_SYSNAME_WIN32;SO_WIN32;WIN32_LEAN_AND_MEAN;L_ENDIAN;NO_WINDOWS_BRAINDEATH") - - if (ENABLE_OPENSSL_ENGINES) - link_libraries(crypt32) - endif() - - add_definitions( - -DOPENSSL_RAND_SEED_OS # ${OPENSSL_SOURCES_DIR}/crypto/rand/rand_win.c - ) - -elseif ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - add_definitions( - # In order for "crypto/mem_sec.c" to compile on LSB - -DOPENSSL_NO_SECURE_MEMORY - - # The "OPENSSL_RAND_SEED_OS" value implies a syscall() to - # "__NR_getrandom" (i.e. system call "getentropy(2)") in - # "rand_unix.c", which is not available in LSB. - -DOPENSSL_RAND_SEED_DEVRANDOM - ) - -else() - # Fixes error "OpenSSL error: error:2406C06E:random number - # generator:RAND_DRBG_instantiate:error retrieving entropy" that was - # present in Orthanc 1.6.0, if statically linking on Ubuntu 18.04 - add_definitions( - -DOPENSSL_RAND_SEED_OS - ) -endif() - - -set_source_files_properties( - ${OPENSSL_SOURCES} - PROPERTIES COMPILE_DEFINITIONS - "${OPENSSL_DEFINITIONS};DSO_NONE" - ) diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,684 +0,0 @@ -## -## This is a CMake configuration file that configures the core -## libraries of Orthanc. This file can be used by external projects so -## as to gain access to the Orthanc APIs (the most prominent examples -## are currently "Stone of Orthanc" and "Orthanc for whole-slide -## imaging plugin"). -## - - -##################################################################### -## Configuration of the components -##################################################################### - -# Path to the root folder of the Orthanc distribution -set(ORTHANC_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) - -# Some basic inclusions -include(CMakePushCheckState) -include(CheckFunctionExists) -include(CheckIncludeFile) -include(CheckIncludeFileCXX) -include(CheckIncludeFiles) -include(CheckLibraryExists) -include(CheckStructHasMember) -include(CheckSymbolExists) -include(CheckTypeSize) -include(FindPythonInterp) - -include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/DownloadPackage.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake) - - -##################################################################### -## Disable unneeded macros -##################################################################### - -if (NOT ENABLE_SQLITE) - unset(USE_SYSTEM_SQLITE CACHE) - add_definitions(-DORTHANC_ENABLE_SQLITE=0) -endif() - -if (NOT ENABLE_CRYPTO_OPTIONS) - unset(ENABLE_SSL CACHE) - unset(ENABLE_PKCS11 CACHE) - unset(ENABLE_OPENSSL_ENGINES CACHE) - unset(USE_SYSTEM_OPENSSL CACHE) - unset(USE_SYSTEM_LIBP11 CACHE) - add_definitions( - -DORTHANC_ENABLE_SSL=0 - -DORTHANC_ENABLE_PKCS11=0 - ) -endif() - -if (NOT ENABLE_WEB_CLIENT) - unset(USE_SYSTEM_CURL CACHE) - add_definitions(-DORTHANC_ENABLE_CURL=0) -endif() - -if (NOT ENABLE_WEB_SERVER) - unset(ENABLE_CIVETWEB CACHE) - unset(USE_SYSTEM_CIVETWEB CACHE) - unset(USE_SYSTEM_MONGOOSE CACHE) - add_definitions( - -DORTHANC_ENABLE_CIVETWEB=0 - -DORTHANC_ENABLE_MONGOOSE=0 - ) -endif() - -if (NOT ENABLE_JPEG) - unset(USE_SYSTEM_LIBJPEG CACHE) - add_definitions(-DORTHANC_ENABLE_JPEG=0) -endif() - -if (NOT ENABLE_ZLIB) - unset(USE_SYSTEM_ZLIB CACHE) - add_definitions(-DORTHANC_ENABLE_ZLIB=0) -endif() - -if (NOT ENABLE_PNG) - unset(USE_SYSTEM_LIBPNG CACHE) - add_definitions(-DORTHANC_ENABLE_PNG=0) -endif() - -if (NOT ENABLE_LUA) - unset(USE_SYSTEM_LUA CACHE) - unset(ENABLE_LUA_MODULES CACHE) - add_definitions(-DORTHANC_ENABLE_LUA=0) -endif() - -if (NOT ENABLE_PUGIXML) - unset(USE_SYSTEM_PUGIXML CACHE) - add_definitions(-DORTHANC_ENABLE_PUGIXML=0) -endif() - -if (NOT ENABLE_LOCALE) - unset(BOOST_LOCALE_BACKEND CACHE) - add_definitions(-DORTHANC_ENABLE_LOCALE=0) -endif() - -if (NOT ENABLE_GOOGLE_TEST) - unset(USE_SYSTEM_GOOGLE_TEST CACHE) - unset(USE_GOOGLE_TEST_DEBIAN_PACKAGE CACHE) -endif() - -if (NOT ENABLE_DCMTK) - add_definitions( - -DORTHANC_ENABLE_DCMTK=0 - -DORTHANC_ENABLE_DCMTK_NETWORKING=0 - -DORTHANC_ENABLE_DCMTK_TRANSCODING=0 - ) - unset(DCMTK_DICTIONARY_DIR CACHE) - unset(DCMTK_VERSION CACHE) - unset(USE_DCMTK_362_PRIVATE_DIC CACHE) - unset(USE_SYSTEM_DCMTK CACHE) - unset(ENABLE_DCMTK_JPEG CACHE) - unset(ENABLE_DCMTK_JPEG_LOSSLESS CACHE) -endif() - - -##################################################################### -## List of source files -##################################################################### - -set(ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Cache/MemoryCache.cpp - ${ORTHANC_ROOT}/Core/Cache/MemoryObjectCache.cpp - ${ORTHANC_ROOT}/Core/Cache/MemoryStringCache.cpp - ${ORTHANC_ROOT}/Core/ChunkedBuffer.cpp - ${ORTHANC_ROOT}/Core/DicomFormat/DicomTag.cpp - ${ORTHANC_ROOT}/Core/EnumerationDictionary.h - ${ORTHANC_ROOT}/Core/Enumerations.cpp - ${ORTHANC_ROOT}/Core/FileStorage/MemoryStorageArea.cpp - ${ORTHANC_ROOT}/Core/HttpServer/MultipartStreamReader.cpp - ${ORTHANC_ROOT}/Core/HttpServer/StringMatcher.cpp - ${ORTHANC_ROOT}/Core/Logging.cpp - ${ORTHANC_ROOT}/Core/SerializationToolbox.cpp - ${ORTHANC_ROOT}/Core/Toolbox.cpp - ${ORTHANC_ROOT}/Core/WebServiceParameters.cpp - ) - -if (ENABLE_MODULE_IMAGES) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Images/Font.cpp - ${ORTHANC_ROOT}/Core/Images/FontRegistry.cpp - ${ORTHANC_ROOT}/Core/Images/IImageWriter.cpp - ${ORTHANC_ROOT}/Core/Images/Image.cpp - ${ORTHANC_ROOT}/Core/Images/ImageAccessor.cpp - ${ORTHANC_ROOT}/Core/Images/ImageBuffer.cpp - ${ORTHANC_ROOT}/Core/Images/ImageProcessing.cpp - ${ORTHANC_ROOT}/Core/Images/PamReader.cpp - ${ORTHANC_ROOT}/Core/Images/PamWriter.cpp - ) -endif() - -if (ENABLE_MODULE_DICOM) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/DicomFormat/DicomArray.cpp - ${ORTHANC_ROOT}/Core/DicomFormat/DicomImageInformation.cpp - ${ORTHANC_ROOT}/Core/DicomFormat/DicomInstanceHasher.cpp - ${ORTHANC_ROOT}/Core/DicomFormat/DicomIntegerPixelAccessor.cpp - ${ORTHANC_ROOT}/Core/DicomFormat/DicomMap.cpp - ${ORTHANC_ROOT}/Core/DicomFormat/DicomValue.cpp - ) -endif() - -if (ENABLE_MODULE_JOBS) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/JobsEngine/GenericJobUnserializer.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/JobInfo.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/JobStatus.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/JobStepResult.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/Operations/JobOperationValues.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/Operations/LogJobOperation.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/SetOfCommandsJob.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/SetOfInstancesJob.cpp - ) -endif() - - - -##################################################################### -## Configuration of optional third-party dependencies -##################################################################### - - -## -## Embedded database: SQLite -## - -if (ENABLE_SQLITE) - include(${CMAKE_CURRENT_LIST_DIR}/SQLiteConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_SQLITE=1) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/SQLite/Connection.cpp - ${ORTHANC_ROOT}/Core/SQLite/FunctionContext.cpp - ${ORTHANC_ROOT}/Core/SQLite/Statement.cpp - ${ORTHANC_ROOT}/Core/SQLite/StatementId.cpp - ${ORTHANC_ROOT}/Core/SQLite/StatementReference.cpp - ${ORTHANC_ROOT}/Core/SQLite/Transaction.cpp - ) -endif() - - -## -## Cryptography: OpenSSL and libp11 -## Must be above "ENABLE_WEB_CLIENT" and "ENABLE_WEB_SERVER" -## - -if (ENABLE_CRYPTO_OPTIONS) - if (ENABLE_SSL) - include(${CMAKE_CURRENT_LIST_DIR}/OpenSslConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_SSL=1) - else() - unset(ENABLE_OPENSSL_ENGINES CACHE) - unset(USE_SYSTEM_OPENSSL CACHE) - add_definitions(-DORTHANC_ENABLE_SSL=0) - endif() - - if (ENABLE_PKCS11) - if (ENABLE_SSL) - include(${CMAKE_CURRENT_LIST_DIR}/LibP11Configuration.cmake) - - add_definitions(-DORTHANC_ENABLE_PKCS11=1) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Pkcs11.cpp - ) - else() - message(FATAL_ERROR "OpenSSL is required to enable PKCS#11 support") - endif() - else() - add_definitions(-DORTHANC_ENABLE_PKCS11=0) - endif() -endif() - - -## -## HTTP client: libcurl -## - -if (ENABLE_WEB_CLIENT) - include(${CMAKE_CURRENT_LIST_DIR}/LibCurlConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_CURL=1) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/HttpClient.cpp - ) -endif() - - -## -## HTTP server: Mongoose 3.8 or Civetweb -## - -if (ENABLE_WEB_SERVER) - if (ENABLE_CIVETWEB) - include(${CMAKE_CURRENT_LIST_DIR}/CivetwebConfiguration.cmake) - add_definitions( - -DORTHANC_ENABLE_CIVETWEB=1 - -DORTHANC_ENABLE_MONGOOSE=0 - ) - else() - include(${CMAKE_CURRENT_LIST_DIR}/MongooseConfiguration.cmake) - add_definitions( - -DORTHANC_ENABLE_CIVETWEB=0 - -DORTHANC_ENABLE_MONGOOSE=1 - ) - endif() - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/HttpServer/BufferHttpSender.cpp - ${ORTHANC_ROOT}/Core/HttpServer/FilesystemHttpHandler.cpp - ${ORTHANC_ROOT}/Core/HttpServer/FilesystemHttpSender.cpp - ${ORTHANC_ROOT}/Core/HttpServer/HttpContentNegociation.cpp - ${ORTHANC_ROOT}/Core/HttpServer/HttpFileSender.cpp - ${ORTHANC_ROOT}/Core/HttpServer/HttpOutput.cpp - ${ORTHANC_ROOT}/Core/HttpServer/HttpServer.cpp - ${ORTHANC_ROOT}/Core/HttpServer/HttpStreamTranscoder.cpp - ${ORTHANC_ROOT}/Core/HttpServer/HttpToolbox.cpp - ${ORTHANC_ROOT}/Core/HttpServer/StringHttpOutput.cpp - ${ORTHANC_ROOT}/Core/RestApi/RestApi.cpp - ${ORTHANC_ROOT}/Core/RestApi/RestApiCall.cpp - ${ORTHANC_ROOT}/Core/RestApi/RestApiGetCall.cpp - ${ORTHANC_ROOT}/Core/RestApi/RestApiHierarchy.cpp - ${ORTHANC_ROOT}/Core/RestApi/RestApiOutput.cpp - ${ORTHANC_ROOT}/Core/RestApi/RestApiPath.cpp - ) -endif() - - -## -## JPEG support: libjpeg -## - -if (ENABLE_JPEG) - if (NOT ENABLE_MODULE_IMAGES) - message(FATAL_ERROR "Image processing primitives must be enabled if enabling libjpeg support") - endif() - - include(${CMAKE_CURRENT_LIST_DIR}/LibJpegConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_JPEG=1) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Images/JpegErrorManager.cpp - ${ORTHANC_ROOT}/Core/Images/JpegReader.cpp - ${ORTHANC_ROOT}/Core/Images/JpegWriter.cpp - ) -endif() - - -## -## zlib support -## - -if (ENABLE_ZLIB) - include(${CMAKE_CURRENT_LIST_DIR}/ZlibConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_ZLIB=1) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Compression/DeflateBaseCompressor.cpp - ${ORTHANC_ROOT}/Core/Compression/GzipCompressor.cpp - ${ORTHANC_ROOT}/Core/Compression/ZlibCompressor.cpp - ) - - if (NOT ORTHANC_SANDBOXED) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Compression/HierarchicalZipWriter.cpp - ${ORTHANC_ROOT}/Core/Compression/ZipWriter.cpp - ${ORTHANC_ROOT}/Core/FileStorage/StorageAccessor.cpp - ) - endif() -endif() - - -## -## PNG support: libpng (in conjunction with zlib) -## - -if (ENABLE_PNG) - if (NOT ENABLE_ZLIB) - message(FATAL_ERROR "Support for zlib must be enabled if enabling libpng support") - endif() - - if (NOT ENABLE_MODULE_IMAGES) - message(FATAL_ERROR "Image processing primitives must be enabled if enabling libpng support") - endif() - - include(${CMAKE_CURRENT_LIST_DIR}/LibPngConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_PNG=1) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Images/PngReader.cpp - ${ORTHANC_ROOT}/Core/Images/PngWriter.cpp - ) -endif() - - -## -## Lua support -## - -if (ENABLE_LUA) - include(${CMAKE_CURRENT_LIST_DIR}/LuaConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_LUA=1) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Lua/LuaContext.cpp - ${ORTHANC_ROOT}/Core/Lua/LuaFunctionCall.cpp - ) -endif() - - -## -## XML support: pugixml -## - -if (ENABLE_PUGIXML) - include(${CMAKE_CURRENT_LIST_DIR}/PugixmlConfiguration.cmake) - add_definitions(-DORTHANC_ENABLE_PUGIXML=1) -endif() - - -## -## Locale support -## - -if (ENABLE_LOCALE) - if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - # In WebAssembly or asm.js, we rely on the version of iconv that - # is shipped with the stdlib - unset(BOOST_LOCALE_BACKEND CACHE) - else() - if (BOOST_LOCALE_BACKEND STREQUAL "gcc") - elseif (BOOST_LOCALE_BACKEND STREQUAL "libiconv") - include(${CMAKE_CURRENT_LIST_DIR}/LibIconvConfiguration.cmake) - elseif (BOOST_LOCALE_BACKEND STREQUAL "icu") - include(${CMAKE_CURRENT_LIST_DIR}/LibIcuConfiguration.cmake) - elseif (BOOST_LOCALE_BACKEND STREQUAL "wconv") - message("Using Microsoft Window's wconv") - else() - message(FATAL_ERROR "Invalid value for BOOST_LOCALE_BACKEND: ${BOOST_LOCALE_BACKEND}") - endif() - endif() - - add_definitions(-DORTHANC_ENABLE_LOCALE=1) -endif() - - -## -## Google Test for unit testing -## - -if (ENABLE_GOOGLE_TEST) - include(${CMAKE_CURRENT_LIST_DIR}/GoogleTestConfiguration.cmake) -endif() - - - -##################################################################### -## Inclusion of mandatory third-party dependencies -##################################################################### - -include(${CMAKE_CURRENT_LIST_DIR}/JsonCppConfiguration.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/UuidConfiguration.cmake) - -# We put Boost as the last dependency, as it is the heaviest to -# configure, which allows to quickly spot problems when configuring -# static builds in other dependencies -include(${CMAKE_CURRENT_LIST_DIR}/BoostConfiguration.cmake) - - -##################################################################### -## Optional configuration of DCMTK -##################################################################### - -if (ENABLE_DCMTK) - if (NOT ENABLE_LOCALE) - message(FATAL_ERROR "Support for locales must be enabled if enabling DCMTK support") - endif() - - if (NOT ENABLE_MODULE_DICOM) - message(FATAL_ERROR "DICOM module must be enabled if enabling DCMTK support") - endif() - - include(${CMAKE_CURRENT_LIST_DIR}/DcmtkConfiguration.cmake) - - add_definitions(-DORTHANC_ENABLE_DCMTK=1) - - if (ENABLE_DCMTK_JPEG) - add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG=1) - else() - add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG=0) - endif() - - if (ENABLE_DCMTK_JPEG_LOSSLESS) - add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS=1) - else() - add_definitions(-DORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS=0) - endif() - - set(ORTHANC_DICOM_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/DicomParsing/DicomModification.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/DicomWebJsonVisitor.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/FromDcmtkBridge.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/ParsedDicomDir.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/ParsedDicomFile.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/ToDcmtkBridge.cpp - - ${ORTHANC_ROOT}/Core/DicomParsing/Internals/DicomFrameIndex.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/Internals/DicomImageDecoder.cpp - ) - - if (NOT ORTHANC_SANDBOXED) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/DicomParsing/DicomDirWriter.cpp - ) - endif() - - if (ENABLE_DCMTK_NETWORKING) - add_definitions(-DORTHANC_ENABLE_DCMTK_NETWORKING=1) - list(APPEND ORTHANC_DICOM_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/DicomNetworking/DicomAssociation.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/DicomAssociationParameters.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/DicomControlUserConnection.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/DicomFindAnswers.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/DicomServer.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/DicomStoreUserConnection.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/CommandDispatcher.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/FindScp.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/MoveScp.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/GetScp.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/StoreScp.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/RemoteModalityParameters.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp - ) - else() - add_definitions(-DORTHANC_ENABLE_DCMTK_NETWORKING=0) - endif() - - # New in Orthanc 1.6.0 - if (ENABLE_DCMTK_TRANSCODING) - add_definitions(-DORTHANC_ENABLE_DCMTK_TRANSCODING=1) - list(APPEND ORTHANC_DICOM_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/DicomParsing/DcmtkTranscoder.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/IDicomTranscoder.cpp - ${ORTHANC_ROOT}/Core/DicomParsing/MemoryBufferTranscoder.cpp - ) - else() - add_definitions(-DORTHANC_ENABLE_DCMTK_TRANSCODING=0) - endif() - - if (STANDALONE_BUILD AND NOT HAS_EMBEDDED_RESOURCES) - EmbedResources( - ${DCMTK_DICTIONARIES} - ) - list(APPEND ORTHANC_DICOM_SOURCES_DEPENDENCIES - ${AUTOGENERATED_SOURCES} - ) - endif() -endif() - - -##################################################################### -## Configuration of the C/C++ macros -##################################################################### - -add_definitions( - -DORTHANC_API_VERSION=${ORTHANC_API_VERSION} - -DORTHANC_DATABASE_VERSION=${ORTHANC_DATABASE_VERSION} - -DORTHANC_DEFAULT_DICOM_ENCODING=Encoding_Latin1 - -DORTHANC_ENABLE_BASE64=1 - -DORTHANC_ENABLE_MD5=1 - -DORTHANC_MAXIMUM_TAG_LENGTH=256 - -DORTHANC_VERSION="${ORTHANC_VERSION}" - ) - - -if (ORTHANC_SANDBOXED) - add_definitions( - -DORTHANC_SANDBOXED=1 - -DORTHANC_ENABLE_LOGGING_PLUGIN=0 - ) - - if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") - add_definitions( - -DORTHANC_ENABLE_LOGGING=1 - -DORTHANC_ENABLE_LOGGING_STDIO=1 - ) - else() - add_definitions( - -DORTHANC_ENABLE_LOGGING=0 - ) - endif() - -else() - add_definitions( - -DORTHANC_ENABLE_LOGGING=1 - -DORTHANC_ENABLE_LOGGING_STDIO=0 - -DORTHANC_SANDBOXED=0 - ) - - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/Cache/SharedArchive.cpp - ${ORTHANC_ROOT}/Core/FileBuffer.cpp - ${ORTHANC_ROOT}/Core/FileStorage/FilesystemStorage.cpp - ${ORTHANC_ROOT}/Core/MetricsRegistry.cpp - ${ORTHANC_ROOT}/Core/MultiThreading/RunnableWorkersPool.cpp - ${ORTHANC_ROOT}/Core/MultiThreading/Semaphore.cpp - ${ORTHANC_ROOT}/Core/MultiThreading/SharedMessageQueue.cpp - ${ORTHANC_ROOT}/Core/SharedLibrary.cpp - ${ORTHANC_ROOT}/Core/SystemToolbox.cpp - ${ORTHANC_ROOT}/Core/TemporaryFile.cpp - ) - - if (ENABLE_MODULE_JOBS) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/JobsEngine/JobsEngine.cpp - ${ORTHANC_ROOT}/Core/JobsEngine/JobsRegistry.cpp - ) - endif() -endif() - - -if (HAS_EMBEDDED_RESOURCES) - add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=1) - - if (ENABLE_WEB_SERVER) - list(APPEND ORTHANC_CORE_SOURCES_INTERNAL - ${ORTHANC_ROOT}/Core/HttpServer/EmbeddedResourceHttpHandler.cpp - ) - endif() -else() - add_definitions(-DORTHANC_HAS_EMBEDDED_RESOURCES=0) -endif() - - - -##################################################################### -## Configuration of Orthanc versioning macros (new in Orthanc 1.5.0) -##################################################################### - -if (ORTHANC_VERSION STREQUAL "mainline") - set(ORTHANC_VERSION_MAJOR "999") - set(ORTHANC_VERSION_MINOR "999") - set(ORTHANC_VERSION_REVISION "999") -else() - string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)$" "\\1" ORTHANC_VERSION_MAJOR ${ORTHANC_VERSION}) - string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)$" "\\2" ORTHANC_VERSION_MINOR ${ORTHANC_VERSION}) - string(REGEX REPLACE "^([0-9]*)\\.([0-9]*)\\.([0-9]*)$" "\\3" ORTHANC_VERSION_REVISION ${ORTHANC_VERSION}) - - if (NOT ORTHANC_VERSION STREQUAL - "${ORTHANC_VERSION_MAJOR}.${ORTHANC_VERSION_MINOR}.${ORTHANC_VERSION_REVISION}") - message(FATAL_ERROR "Error in the (x.y.z) format of the Orthanc version: ${ORTHANC_VERSION}") - endif() -endif() - -add_definitions( - -DORTHANC_VERSION_MAJOR=${ORTHANC_VERSION_MAJOR} - -DORTHANC_VERSION_MINOR=${ORTHANC_VERSION_MINOR} - -DORTHANC_VERSION_REVISION=${ORTHANC_VERSION_REVISION} - ) - - - -##################################################################### -## Gathering of all the source code -##################################################################### - -# The "xxx_INTERNAL" variables list the source code that belongs to -# the Orthanc project. It can be used to configure precompiled headers -# if using Microsoft Visual Studio. - -# The "xxx_DEPENDENCIES" variables list the source code coming from -# third-party dependencies. - - -set(ORTHANC_CORE_SOURCES_DEPENDENCIES - ${BOOST_SOURCES} - ${CIVETWEB_SOURCES} - ${CURL_SOURCES} - ${JSONCPP_SOURCES} - ${LIBICONV_SOURCES} - ${LIBICU_SOURCES} - ${LIBJPEG_SOURCES} - ${LIBP11_SOURCES} - ${LIBPNG_SOURCES} - ${LUA_SOURCES} - ${MONGOOSE_SOURCES} - ${OPENSSL_SOURCES} - ${PUGIXML_SOURCES} - ${SQLITE_SOURCES} - ${UUID_SOURCES} - ${ZLIB_SOURCES} - - ${ORTHANC_ROOT}/Resources/ThirdParty/md5/md5.c - ${ORTHANC_ROOT}/Resources/ThirdParty/base64/base64.cpp - ) - -if (ENABLE_ZLIB AND NOT ORTHANC_SANDBOXED) - list(APPEND ORTHANC_CORE_SOURCES_DEPENDENCIES - # This is the minizip distribution to create ZIP files using zlib - ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/ioapi.c - ${ORTHANC_ROOT}/Resources/ThirdParty/minizip/zip.c - ) -endif() - - -set(ORTHANC_CORE_SOURCES - ${ORTHANC_CORE_SOURCES_INTERNAL} - ${ORTHANC_CORE_SOURCES_DEPENDENCIES} - ) - -if (ENABLE_DCMTK) - list(APPEND ORTHANC_DICOM_SOURCES_DEPENDENCIES - ${DCMTK_SOURCES} - ) - - set(ORTHANC_DICOM_SOURCES - ${ORTHANC_DICOM_SOURCES_INTERNAL} - ${ORTHANC_DICOM_SOURCES_DEPENDENCIES} - ) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkParameters.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkParameters.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkParameters.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/OrthancFrameworkParameters.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,124 +0,0 @@ -##################################################################### -## Versioning information -##################################################################### - -# Version of the build, should always be "mainline" except in release branches -set(ORTHANC_VERSION "1.7.0") - -# Version of the database schema. History: -# * Orthanc 0.1.0 -> Orthanc 0.3.0 = no versioning -# * Orthanc 0.3.1 = version 2 -# * Orthanc 0.4.0 -> Orthanc 0.7.2 = version 3 -# * Orthanc 0.7.3 -> Orthanc 0.8.4 = version 4 -# * Orthanc 0.8.5 -> Orthanc 0.9.4 = version 5 -# * Orthanc 0.9.5 -> mainline = version 6 -set(ORTHANC_DATABASE_VERSION 6) - -# Version of the Orthanc API, can be retrieved from "/system" URI in -# order to check whether new URI endpoints are available even if using -# the mainline version of Orthanc -set(ORTHANC_API_VERSION "7") - - -##################################################################### -## CMake parameters tunable by the user -##################################################################### - -# Support of static compilation -set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") -set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") -set(STANDALONE_BUILD ON CACHE BOOL "Standalone build (all the resources are embedded, necessary for releases)") - -# Generic parameters of the build -set(ENABLE_CIVETWEB ON CACHE BOOL "Use Civetweb instead of Mongoose (Mongoose was the default embedded HTTP server in Orthanc <= 1.5.1)") -set(ENABLE_PKCS11 OFF CACHE BOOL "Enable PKCS#11 for HTTPS client authentication using hardware security modules and smart cards") -set(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof") -set(ENABLE_SSL ON CACHE BOOL "Include support for SSL") -set(ENABLE_LUA_MODULES OFF CACHE BOOL "Enable support for loading external Lua modules (only meaningful if using static version of the Lua engine)") - -# Parameters to fine-tune linking against system libraries -set(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost") -set(USE_SYSTEM_CIVETWEB ON CACHE BOOL "Use the system version of Civetweb (experimental)") -set(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl") -set(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test") -set(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") -set(USE_SYSTEM_LIBICONV ON CACHE BOOL "Use the system version of libiconv") -set(USE_SYSTEM_LIBICU ON CACHE BOOL "Use the system version of libicu") -set(USE_SYSTEM_LIBJPEG ON CACHE BOOL "Use the system version of libjpeg") -set(USE_SYSTEM_LIBP11 OFF CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)") -set(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of libpng") -set(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua") -set(USE_SYSTEM_MONGOOSE ON CACHE BOOL "Use the system version of Mongoose") -set(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL") -set(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml") -set(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite") -set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs") -set(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib") - -# Parameters specific to DCMTK -set(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") -set(DCMTK_STATIC_VERSION "3.6.5" CACHE STRING "Version of DCMTK to be used in static builds (can be \"3.6.0\", \"3.6.2\", \"3.6.4\", or \"3.6.5\")") -set(USE_DCMTK_362_PRIVATE_DIC ON CACHE BOOL "Use the dictionary of private tags from DCMTK 3.6.2 if using DCMTK 3.6.0") -set(USE_SYSTEM_DCMTK ON CACHE BOOL "Use the system version of DCMTK") -set(ENABLE_DCMTK_LOG ON CACHE BOOL "Enable logging internal to DCMTK") -set(ENABLE_DCMTK_JPEG ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression") -set(ENABLE_DCMTK_JPEG_LOSSLESS ON CACHE BOOL "Enable JPEG-LS (Lossless) decompression") - -# Advanced and distribution-specific parameters -set(USE_GOOGLE_TEST_DEBIAN_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)") -set(SYSTEM_MONGOOSE_USE_CALLBACKS ON CACHE BOOL "The system version of Mongoose uses callbacks (version >= 3.7)") -set(BOOST_LOCALE_BACKEND "libiconv" CACHE STRING "Back-end for locales that is used by Boost (can be \"gcc\", \"libiconv\", \"icu\", or \"wconv\" on Windows)") -set(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)") -set(USE_LEGACY_JSONCPP OFF CACHE BOOL "Use the old branch 0.x.y of JsonCpp, that does not require a C++11 compiler (for LSB and old versions of Visual Studio)") -set(USE_LEGACY_LIBICU OFF CACHE BOOL "Use icu icu4c-58_2, latest version not requiring a C++11 compiler (for LSB and old versions of Visual Studio)") -set(MSVC_MULTIPLE_PROCESSES OFF CACHE BOOL "Add the /MP option to build with multiple processes if using Visual Studio") -set(EMSCRIPTEN_SET_LLVM_WASM_BACKEND OFF CACHE BOOL "Sets the compiler flags required to use the LLVM Web Assembly backend in emscripten") -set(OPENSSL_STATIC_VERSION "1.1.1" CACHE STRING "Version of OpenSSL to be used in static builds (can be \"1.0.2\", or \"1.1.1\")") - -mark_as_advanced(USE_GOOGLE_TEST_DEBIAN_PACKAGE) -mark_as_advanced(SYSTEM_MONGOOSE_USE_CALLBACKS) -mark_as_advanced(USE_PUGIXML) -mark_as_advanced(USE_DCMTK_362_PRIVATE_DIC) - - -##################################################################### -## Internal CMake parameters to enable the optional subcomponents of -## the Orthanc framework -##################################################################### - -# These options must be set to "ON" if compiling Orthanc, but might be -# set to "OFF" by third-party projects if their associated features -# are not required - -set(ENABLE_CRYPTO_OPTIONS OFF CACHE INTERNAL "Show options related to cryptography") -set(ENABLE_JPEG OFF CACHE INTERNAL "Enable support of JPEG") -set(ENABLE_GOOGLE_TEST OFF CACHE INTERNAL "Enable support of Google Test") -set(ENABLE_LOCALE OFF CACHE INTERNAL "Enable support for locales (notably in Boost)") -set(ENABLE_LUA OFF CACHE INTERNAL "Enable support of Lua scripting") -set(ENABLE_PNG OFF CACHE INTERNAL "Enable support of PNG") -set(ENABLE_PUGIXML OFF CACHE INTERNAL "Enable support of XML through Pugixml") -set(ENABLE_SQLITE OFF CACHE INTERNAL "Enable support of SQLite databases") -set(ENABLE_ZLIB OFF CACHE INTERNAL "Enable support of zlib") -set(ENABLE_WEB_CLIENT OFF CACHE INTERNAL "Enable Web client") -set(ENABLE_WEB_SERVER OFF CACHE INTERNAL "Enable embedded Web server") -set(ENABLE_DCMTK OFF CACHE INTERNAL "Enable DCMTK") -set(ENABLE_DCMTK_NETWORKING OFF CACHE INTERNAL "Enable DICOM networking in DCMTK") -set(ENABLE_DCMTK_TRANSCODING OFF CACHE INTERNAL "Enable DICOM transcoding in DCMTK") -set(ENABLE_OPENSSL_ENGINES OFF CACHE INTERNAL "Enable support of engines in OpenSSL") - -set(HAS_EMBEDDED_RESOURCES OFF CACHE INTERNAL - "Whether resources are auto-generated using EmbedResources.py") - -set(ORTHANC_SANDBOXED OFF CACHE INTERNAL - "Whether Orthanc runs inside a sandboxed environment (such as Google NaCl or WebAssembly)") - - -# -# These options can be used to turn off some modules of the Orthanc -# framework, in order to speed up the compilation time of third-party -# projects. -# - -set(ENABLE_MODULE_IMAGES ON CACHE INTERNAL "Enable module for image processing") -set(ENABLE_MODULE_JOBS ON CACHE INTERNAL "Enable module for jobs") -set(ENABLE_MODULE_DICOM ON CACHE INTERNAL "Enable module for DICOM handling") diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/PugixmlConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/PugixmlConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/PugixmlConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/PugixmlConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML) - set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.9) - set(PUGIXML_MD5 "7286ee2ed11376b6b780ced19fae0b64") - set(PUGIXML_URL "http://orthanc.osimis.io/ThirdPartyDownloads/pugixml-1.9.tar.gz") - - DownloadPackage(${PUGIXML_MD5} ${PUGIXML_URL} "${PUGIXML_SOURCES_DIR}") - - include_directories( - ${PUGIXML_SOURCES_DIR}/src - ) - - set(PUGIXML_SOURCES - #${PUGIXML_SOURCES_DIR}/src/vlog_is_on.cc - ${PUGIXML_SOURCES_DIR}/src/pugixml.cpp - ) - - source_group(ThirdParty\\pugixml REGULAR_EXPRESSION ${PUGIXML_SOURCES_DIR}/.*) - -else() - CHECK_INCLUDE_FILE_CXX(pugixml.hpp HAVE_PUGIXML_H) - if (NOT HAVE_PUGIXML_H) - message(FATAL_ERROR "Please install the libpugixml-dev package") - endif() - - link_libraries(pugixml) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/SQLiteConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/SQLiteConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/SQLiteConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/SQLiteConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -if (APPLE) - # Under OS X, the binaries must always be linked against the - # system-wide version of SQLite. Otherwise, if some Orthanc plugin - # also uses its own version of SQLite (such as orthanc-webviewer), - # this results in a crash in "sqlite3_mutex_enter(db->mutex);" (the - # mutex is not initialized), probably because the EXE and the DYNLIB - # share the same memory location for this mutex. - set(SQLITE_STATIC OFF) - -elseif (STATIC_BUILD OR NOT USE_SYSTEM_SQLITE) - set(SQLITE_STATIC ON) -else() - set(SQLITE_STATIC OFF) -endif() - - -if (SQLITE_STATIC) - SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3270100) - SET(SQLITE_MD5 "16717b26358ba81f0bfdac07addc77da") - SET(SQLITE_URL "http://orthanc.osimis.io/ThirdPartyDownloads/sqlite-amalgamation-3270100.zip") - - add_definitions(-DORTHANC_SQLITE_VERSION=3027001) - - DownloadPackage(${SQLITE_MD5} ${SQLITE_URL} "${SQLITE_SOURCES_DIR}") - - set(SQLITE_SOURCES - ${SQLITE_SOURCES_DIR}/sqlite3.c - ) - - add_definitions( - # For SQLite to run in the "Serialized" thread-safe mode - # http://www.sqlite.org/threadsafe.html - -DSQLITE_THREADSAFE=1 - -DSQLITE_OMIT_LOAD_EXTENSION # Disable SQLite plugins - ) - - include_directories( - ${SQLITE_SOURCES_DIR} - ) - - source_group(ThirdParty\\SQLite REGULAR_EXPRESSION ${SQLITE_SOURCES_DIR}/.*) - -else() - CHECK_INCLUDE_FILE(sqlite3.h HAVE_SQLITE_H) - if (NOT HAVE_SQLITE_H) - message(FATAL_ERROR "Please install the libsqlite3-dev package") - endif() - - find_path(SQLITE_INCLUDE_DIR - NAMES sqlite3.h - PATHS - /usr/include - /usr/local/include - ) - message("SQLite include dir: ${SQLITE_INCLUDE_DIR}") - - # Autodetection of the version of SQLite - file(STRINGS "${SQLITE_INCLUDE_DIR}/sqlite3.h" SQLITE_VERSION_NUMBER1 REGEX "#define SQLITE_VERSION_NUMBER.*$") - string(REGEX REPLACE "#define SQLITE_VERSION_NUMBER(.*)$" "\\1" SQLITE_VERSION_NUMBER2 ${SQLITE_VERSION_NUMBER1}) - - # Remove the trailing spaces to convert the string to a proper integer - string(STRIP ${SQLITE_VERSION_NUMBER2} SQLITE_VERSION_NUMBER) - - message("Detected version of SQLite: ${SQLITE_VERSION_NUMBER}") - - IF (${SQLITE_VERSION_NUMBER} LESS 3007000) - # "sqlite3_create_function_v2" is not defined in SQLite < 3.7.0 - message(FATAL_ERROR "SQLite version must be above 3.7.0. Please set the CMake variable USE_SYSTEM_SQLITE to OFF.") - ENDIF() - - add_definitions(-DORTHANC_SQLITE_VERSION=${SQLITE_VERSION_NUMBER}) - - link_libraries(sqlite3) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Uninstall.cmake.in orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Uninstall.cmake.in --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Uninstall.cmake.in 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/Uninstall.cmake.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Code taken from the CMake FAQ -# http://www.cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F - -if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - -file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") -list(REVERSE files) -foreach (file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - if (EXISTS "$ENV{DESTDIR}${file}") - execute_process( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - if(NOT ${rm_retval} EQUAL 0) - message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - endif (NOT ${rm_retval} EQUAL 0) - else (EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - endif (EXISTS "$ENV{DESTDIR}${file}") -endforeach(file) diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/UuidConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/UuidConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/UuidConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/UuidConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - - if (STATIC_BUILD OR NOT USE_SYSTEM_UUID) - SET(E2FSPROGS_SOURCES_DIR ${CMAKE_BINARY_DIR}/e2fsprogs-1.44.5) - SET(E2FSPROGS_URL "http://orthanc.osimis.io/ThirdPartyDownloads/e2fsprogs-1.44.5.tar.gz") - SET(E2FSPROGS_MD5 "8d78b11d04d26c0b2dd149529441fa80") - - if (IS_DIRECTORY "${E2FSPROGS_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() - - DownloadPackage(${E2FSPROGS_MD5} ${E2FSPROGS_URL} "${E2FSPROGS_SOURCES_DIR}") - - - ## - ## Patch for OS X, in order to be compatible with Cocoa (used in Stone) - ## - - execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${ORTHANC_ROOT}/Resources/Patches/e2fsprogs-1.44.5-apple.patch - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - - if (FirstRun AND Failure) - message(FATAL_ERROR "Error while patching a file") - endif() - - - include_directories( - BEFORE ${E2FSPROGS_SOURCES_DIR}/lib - ) - - set(UUID_SOURCES - #${E2FSPROGS_SOURCES_DIR}/lib/uuid/tst_uuid.c - #${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_time.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/clear.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/compare.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/copy.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/gen_uuid.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/isnull.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/pack.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/parse.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/unpack.c - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/unparse.c - ) - - check_include_file("net/if.h" HAVE_NET_IF_H) - check_include_file("net/if_dl.h" HAVE_NET_IF_DL_H) - check_include_file("netinet/in.h" HAVE_NETINET_IN_H) - check_include_file("stdlib.h" HAVE_STDLIB_H) - check_include_file("sys/file.h" HAVE_SYS_FILE_H) - check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) - check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H) - check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H) - check_include_file("sys/sockio.h" HAVE_SYS_SOCKIO_H) - check_include_file("sys/syscall.h" HAVE_SYS_SYSCALL_H) - check_include_file("sys/time.h" HAVE_SYS_TIME_H) - check_include_file("sys/un.h" HAVE_SYS_UN_H) - check_include_file("unistd.h" HAVE_UNISTD_H) - - if (NOT HAVE_NET_IF_H) # This is the case of OpenBSD - unset(HAVE_NET_IF_H CACHE) - check_include_files("sys/socket.h;net/if.h" HAVE_NET_IF_H) - endif() - - if (NOT HAVE_NETINET_TCP_H) # This is the case of OpenBSD - unset(HAVE_NETINET_TCP_H CACHE) - check_include_files("sys/socket.h;netinet/tcp.h" HAVE_NETINET_TCP_H) - endif() - - if (NOT EXISTS ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h) - file(WRITE ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake " -#cmakedefine HAVE_NET_IF_H \@HAVE_NET_IF_H\@ -#cmakedefine HAVE_NET_IF_DL_H \@HAVE_NET_IF_DL_H\@ -#cmakedefine HAVE_NETINET_IN_H \@HAVE_NETINET_IN_H\@ -#cmakedefine HAVE_STDLIB_H \@HAVE_STDLIB_H \@ -#cmakedefine HAVE_SYS_FILE_H \@HAVE_SYS_FILE_H\@ -#cmakedefine HAVE_SYS_IOCTL_H \@HAVE_SYS_IOCTL_H\@ -#cmakedefine HAVE_SYS_RESOURCE_H \@HAVE_SYS_RESOURCE_H\@ -#cmakedefine HAVE_SYS_SOCKET_H \@HAVE_SYS_SOCKET_H\@ -#cmakedefine HAVE_SYS_SOCKIO_H \@HAVE_SYS_SOCKIO_H\@ -#cmakedefine HAVE_SYS_SYSCALL_H \@HAVE_SYS_SYSCALL_H\@ -#cmakedefine HAVE_SYS_TIME_H \@HAVE_SYS_TIME_H\@ -#cmakedefine HAVE_SYS_UN_H \@HAVE_SYS_UN_H\@ -#cmakedefine HAVE_UNISTD_H \@HAVE_UNISTD_H\@ -") - endif() - - configure_file( - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h - ) - - configure_file( - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h.in - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h - ) - - if (NOT EXISTS ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h) - file(WRITE - ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h - "#include \n") - endif() - - source_group(ThirdParty\\uuid REGULAR_EXPRESSION ${E2FSPROGS_SOURCES_DIR}/.*) - - else() - CHECK_INCLUDE_FILE(uuid/uuid.h HAVE_UUID_H) - if (NOT HAVE_UUID_H) - message(FATAL_ERROR "Please install uuid-dev, e2fsprogs (OpenBSD) or e2fsprogs-libuuid (FreeBSD)") - endif() - - find_library(LIBUUID uuid - PATHS - /usr/lib - /usr/local/lib - ) - - check_library_exists(${LIBUUID} uuid_generate_random "" HAVE_LIBUUID) - if (NOT HAVE_LIBUUID) - message(FATAL_ERROR "Unable to find the uuid library") - endif() - - link_libraries(${LIBUUID}) - endif() - -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/VisualStudioPrecompiledHeaders.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/VisualStudioPrecompiledHeaders.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/VisualStudioPrecompiledHeaders.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/VisualStudioPrecompiledHeaders.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -macro(ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS PrecompiledHeaders PrecompiledSource Sources Target) - get_filename_component(PrecompiledBasename ${PrecompiledHeaders} NAME_WE) - set(PrecompiledBinary "${PrecompiledBasename}_${CMAKE_BUILD_TYPE}_${CMAKE_GENERATOR_PLATFORM}.pch") - - set_source_files_properties(${PrecompiledSource} - PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeaders}\" /Fp\"${PrecompiledBinary}\"" - OBJECT_OUTPUTS "${PrecompiledBinary}") - - set_source_files_properties(${${Sources}} - PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeaders}\" /Fp\"${PrecompiledBinary}\"" - OBJECT_DEPENDS "${PrecompiledBinary}") - - set(${Target} ${PrecompiledSource}) -endmacro() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/ZlibConfiguration.cmake orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/ZlibConfiguration.cmake --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/ZlibConfiguration.cmake 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/CMake/ZlibConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB) - SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.11) - SET(ZLIB_URL "http://orthanc.osimis.io/ThirdPartyDownloads/zlib-1.2.11.tar.gz") - SET(ZLIB_MD5 "1c9f62f0778697a09d36121ead88e08e") - - DownloadPackage(${ZLIB_MD5} ${ZLIB_URL} "${ZLIB_SOURCES_DIR}") - - include_directories( - ${ZLIB_SOURCES_DIR} - ) - - list(APPEND ZLIB_SOURCES - ${ZLIB_SOURCES_DIR}/adler32.c - ${ZLIB_SOURCES_DIR}/compress.c - ${ZLIB_SOURCES_DIR}/crc32.c - ${ZLIB_SOURCES_DIR}/deflate.c - ${ZLIB_SOURCES_DIR}/gzclose.c - ${ZLIB_SOURCES_DIR}/gzlib.c - ${ZLIB_SOURCES_DIR}/gzread.c - ${ZLIB_SOURCES_DIR}/gzwrite.c - ${ZLIB_SOURCES_DIR}/infback.c - ${ZLIB_SOURCES_DIR}/inffast.c - ${ZLIB_SOURCES_DIR}/inflate.c - ${ZLIB_SOURCES_DIR}/inftrees.c - ${ZLIB_SOURCES_DIR}/trees.c - ${ZLIB_SOURCES_DIR}/uncompr.c - ${ZLIB_SOURCES_DIR}/zutil.c - ) - - source_group(ThirdParty\\zlib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*) - - if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR - ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") - # "ioapi.c" from zlib (minizip) expects the "IOAPI_NO_64" macro to be set to "true" - # https://ohse.de/uwe/articles/lfs.html - add_definitions( - -DIOAPI_NO_64=1 - ) - endif() - -else() - include(FindZLIB) - include_directories(${ZLIB_INCLUDE_DIRS}) - link_libraries(${ZLIB_LIBRARIES}) -endif() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/EmbedResources.py orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/EmbedResources.py --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/EmbedResources.py 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/EmbedResources.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,440 +0,0 @@ -#!/usr/bin/python - -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2020 Osimis S.A., Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# In addition, as a special exception, the copyright holders of this -# program give permission to link the code of its release with the -# OpenSSL project's "OpenSSL" library (or with modified versions of it -# that use the same license as the "OpenSSL" library), and distribute -# the linked executables. You must obey the GNU General Public License -# in all respects for all of the code used other than "OpenSSL". If you -# modify file(s) with this exception, you may extend this exception to -# your version of the file(s), but you are not obligated to do so. If -# you do not wish to do so, delete this exception statement from your -# version. If you delete this exception statement from all source files -# in the program, then also delete it here. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -import sys -import os -import os.path -import pprint -import re - -UPCASE_CHECK = True -USE_SYSTEM_EXCEPTION = False -EXCEPTION_CLASS = 'OrthancException' -OUT_OF_RANGE_EXCEPTION = '::Orthanc::OrthancException(::Orthanc::ErrorCode_ParameterOutOfRange)' -INEXISTENT_PATH_EXCEPTION = '::Orthanc::OrthancException(::Orthanc::ErrorCode_InexistentItem)' -NAMESPACE = 'Orthanc' - -ARGS = [] -for i in range(len(sys.argv)): - if not sys.argv[i].startswith('--'): - ARGS.append(sys.argv[i]) - elif sys.argv[i].lower() == '--no-upcase-check': - UPCASE_CHECK = False - elif sys.argv[i].lower() == '--system-exception': - USE_SYSTEM_EXCEPTION = True - EXCEPTION_CLASS = '::std::runtime_error' - OUT_OF_RANGE_EXCEPTION = '%s("Parameter out of range")' % EXCEPTION_CLASS - INEXISTENT_PATH_EXCEPTION = '%s("Unknown path in a directory resource")' % EXCEPTION_CLASS - elif sys.argv[i].startswith('--namespace='): - NAMESPACE = sys.argv[i][sys.argv[i].find('=') + 1 : ] - -if len(ARGS) < 2 or len(ARGS) % 2 != 0: - print ('Usage:') - print ('python %s [--no-upcase-check] [--system-exception] [--namespace=] [ ]*' % sys.argv[0]) - exit(-1) - -TARGET_BASE_FILENAME = ARGS[1] -SOURCES = ARGS[2:] - -try: - # Make sure the destination directory exists - os.makedirs(os.path.normpath(os.path.join(TARGET_BASE_FILENAME, '..'))) -except: - pass - - -##################################################################### -## Read each resource file -##################################################################### - -def CheckNoUpcase(s): - global UPCASE_CHECK - if (UPCASE_CHECK and - re.search('[A-Z]', s) != None): - raise Exception("Path in a directory with an upcase letter: %s" % s) - -resources = {} - -counter = 0 -i = 0 -while i < len(SOURCES): - resourceName = SOURCES[i].upper() - pathName = SOURCES[i + 1] - - if not os.path.exists(pathName): - raise Exception("Non existing path: %s" % pathName) - - if resourceName in resources: - raise Exception("Twice the same resource: " + resourceName) - - if os.path.isdir(pathName): - # The resource is a directory: Recursively explore its files - content = {} - for root, dirs, files in os.walk(pathName): - dirs.sort() - files.sort() - base = os.path.relpath(root, pathName) - - # Fix issue #24 (Build fails on OSX when directory has .DS_Store files): - # Ignore folders whose name starts with a dot (".") - if base.find('/.') != -1: - print('Ignoring folder: %s' % root) - continue - - for f in files: - if f.find('~') == -1: # Ignore Emacs backup files - if base == '.': - r = f - else: - r = os.path.join(base, f) - - CheckNoUpcase(r) - r = '/' + r.replace('\\', '/') - if r in content: - raise Exception("Twice the same filename (check case): " + r) - - content[r] = { - 'Filename' : os.path.join(root, f), - 'Index' : counter - } - counter += 1 - - resources[resourceName] = { - 'Type' : 'Directory', - 'Files' : content - } - - elif os.path.isfile(pathName): - resources[resourceName] = { - 'Type' : 'File', - 'Index' : counter, - 'Filename' : pathName - } - counter += 1 - - else: - raise Exception("Not a regular file, nor a directory: " + pathName) - - i += 2 - -#pprint.pprint(resources) - - -##################################################################### -## Write .h header -##################################################################### - -header = open(TARGET_BASE_FILENAME + '.h', 'w') - -header.write(""" -#pragma once - -#include -#include - -#if defined(_MSC_VER) -# pragma warning(disable: 4065) // "Switch statement contains 'default' but no 'case' labels" -#endif - -namespace %s -{ - namespace EmbeddedResources - { - enum FileResourceId - { -""" % NAMESPACE) - -isFirst = True -for name in resources: - if resources[name]['Type'] == 'File': - if isFirst: - isFirst = False - else: - header.write(',\n') - header.write(' %s' % name) - -header.write(""" - }; - - enum DirectoryResourceId - { -""") - -isFirst = True -for name in resources: - if resources[name]['Type'] == 'Directory': - if isFirst: - isFirst = False - else: - header.write(',\n') - header.write(' %s' % name) - -header.write(""" - }; - - const void* GetFileResourceBuffer(FileResourceId id); - size_t GetFileResourceSize(FileResourceId id); - void GetFileResource(std::string& result, FileResourceId id); - - const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path); - size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path); - void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path); - - void ListResources(std::list& result, DirectoryResourceId id); - } -} -""") -header.close() - - - -##################################################################### -## Write the resource content in the .cpp source -##################################################################### - -PYTHON_MAJOR_VERSION = sys.version_info[0] - -def WriteResource(cpp, item): - cpp.write(' static const uint8_t resource%dBuffer[] = {' % item['Index']) - - f = open(item['Filename'], "rb") - content = f.read() - f.close() - - # http://stackoverflow.com/a/1035360 - pos = 0 - buffer = [] # instead of appending a few bytes at a time to the cpp file, - # we first append each chunk to a list, join it and write it - # to the file. We've measured that it was 2-3 times faster in python3. - # Note that speed is important since if generation is too slow, - # cmake might try to compile the EmbeddedResources.cpp file while it is - # still being generated ! - for b in content: - if PYTHON_MAJOR_VERSION == 2: - c = ord(b[0]) - else: - c = b - - if pos > 0: - buffer.append(",") - - if (pos % 16) == 0: - buffer.append("\n") - - if c < 0: - raise Exception("Internal error") - - buffer.append("0x%02x" % c) - pos += 1 - - cpp.write("".join(buffer)) - # Zero-size array are disallowed, so we put one single void character in it. - if pos == 0: - cpp.write(' 0') - - cpp.write(' };\n') - cpp.write(' static const size_t resource%dSize = %d;\n' % (item['Index'], pos)) - - -cpp = open(TARGET_BASE_FILENAME + '.cpp', 'w') - -cpp.write('#include "%s.h"\n' % os.path.basename(TARGET_BASE_FILENAME)) - -if USE_SYSTEM_EXCEPTION: - cpp.write('#include ') -else: - cpp.write('#include "%s/Core/OrthancException.h"' % os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -cpp.write(""" -#include -#include - -namespace %s -{ - namespace EmbeddedResources - { -""" % NAMESPACE) - - -for name in resources: - if resources[name]['Type'] == 'File': - WriteResource(cpp, resources[name]) - else: - for f in resources[name]['Files']: - WriteResource(cpp, resources[name]['Files'][f]) - - - -##################################################################### -## Write the accessors to the file resources in .cpp -##################################################################### - -cpp.write(""" - const void* GetFileResourceBuffer(FileResourceId id) - { - switch (id) - { -""") -for name in resources: - if resources[name]['Type'] == 'File': - cpp.write(' case %s:\n' % name) - cpp.write(' return resource%dBuffer;\n' % resources[name]['Index']) - -cpp.write(""" - default: - throw %s; - } - } - - size_t GetFileResourceSize(FileResourceId id) - { - switch (id) - { -""" % OUT_OF_RANGE_EXCEPTION) - -for name in resources: - if resources[name]['Type'] == 'File': - cpp.write(' case %s:\n' % name) - cpp.write(' return resource%dSize;\n' % resources[name]['Index']) - -cpp.write(""" - default: - throw %s; - } - } -""" % OUT_OF_RANGE_EXCEPTION) - - - -##################################################################### -## Write the accessors to the directory resources in .cpp -##################################################################### - -cpp.write(""" - const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path) - { - switch (id) - { -""") - -for name in resources: - if resources[name]['Type'] == 'Directory': - cpp.write(' case %s:\n' % name) - isFirst = True - for path in resources[name]['Files']: - cpp.write(' if (!strcmp(path, "%s"))\n' % path) - cpp.write(' return resource%dBuffer;\n' % resources[name]['Files'][path]['Index']) - cpp.write(' throw %s;\n\n' % INEXISTENT_PATH_EXCEPTION) - -cpp.write(""" default: - throw %s; - } - } - - size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path) - { - switch (id) - { -""" % OUT_OF_RANGE_EXCEPTION) - -for name in resources: - if resources[name]['Type'] == 'Directory': - cpp.write(' case %s:\n' % name) - isFirst = True - for path in resources[name]['Files']: - cpp.write(' if (!strcmp(path, "%s"))\n' % path) - cpp.write(' return resource%dSize;\n' % resources[name]['Files'][path]['Index']) - cpp.write(' throw %s;\n\n' % INEXISTENT_PATH_EXCEPTION) - -cpp.write(""" default: - throw %s; - } - } -""" % OUT_OF_RANGE_EXCEPTION) - - - - -##################################################################### -## List the resources in a directory -##################################################################### - -cpp.write(""" - void ListResources(std::list& result, DirectoryResourceId id) - { - result.clear(); - - switch (id) - { -""") - -for name in resources: - if resources[name]['Type'] == 'Directory': - cpp.write(' case %s:\n' % name) - for path in sorted(resources[name]['Files']): - cpp.write(' result.push_back("%s");\n' % path) - cpp.write(' break;\n\n') - -cpp.write(""" default: - throw %s; - } - } -""" % OUT_OF_RANGE_EXCEPTION) - - - - -##################################################################### -## Write the convenience wrappers in .cpp -##################################################################### - -cpp.write(""" - void GetFileResource(std::string& result, FileResourceId id) - { - size_t size = GetFileResourceSize(id); - result.resize(size); - if (size > 0) - memcpy(&result[0], GetFileResourceBuffer(id), size); - } - - void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path) - { - size_t size = GetDirectoryResourceSize(id, path); - result.resize(size); - if (size > 0) - memcpy(&result[0], GetDirectoryResourceBuffer(id, path), size); - } - } -} -""") -cpp.close() diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.cpp orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.cpp --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.cpp 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,179 +0,0 @@ -/* - base64.cpp and base64.h - - Copyright (C) 2004-2008 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch - - ------------------------------ - This version has been modified (changed the interface + use another decoding algorithm - inspired from https://stackoverflow.com/a/34571089 which was faster) -*/ - -#include "base64.h" -#include -#include - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -void base64_encode(std::string& result, const std::string& stringToEncode) -{ - const unsigned char* bytes_to_encode = reinterpret_cast - (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL); - size_t in_len = stringToEncode.size(); - - result.reserve(result.size() + in_len * 4 / 3 + 10); - - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - result += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - result += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - result += '='; - - } -} - -// old code from René Nyffenegger. This code is slower -void base64_decode_old(std::string& result, const std::string& encoded_string) { - size_t in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - - result.reserve(result.size() + in_len * 3 / 4 + 10); - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - result += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) - result += char_array_3[j]; - } -} - - -// new code from https://stackoverflow.com/a/34571089 -// note that the encoding algorithm from this page was slower (and bugged !) -// this code is not using std::vector::find - -// static init equivalent to: -// decode_indexes.assign(256, -1); -// for (int i=0; i<64; ++i) -// decode_indexes[base64_chars[i]] = i; - -static const int decode_indexes[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - - -void base64_decode(std::string& result, const std::string &stringToDecode) { - - result.reserve(result.size() + stringToDecode.size() * 3 / 4 + 10); - - int val=0, valb=-8; - for (std::string::const_iterator c = stringToDecode.begin(); c != stringToDecode.end(); ++c) - { - size_t index = static_cast(*c); - if (decode_indexes[index] == -1) - break; - val = (val<<6) + decode_indexes[index]; - valb += 6; - if (valb>=0) { - result.push_back(char((val>>valb)&0xFF)); - valb-=8; - } - } -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/base64/base64.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -#include - -void base64_encode(std::string& result, const std::string& stringToEncode); -void base64_decode(std::string& result, const std::string& s); diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.c orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.c --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.c 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,381 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/md5/md5.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,91 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/crypt.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/crypt.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/crypt.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/crypt.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,131 +0,0 @@ -/* crypt.h -- base code for crypt/uncrypt ZIPfile - - - Version 1.01e, February 12th, 2005 - - Copyright (C) 1998-2005 Gilles Vollant - - This code is a modified version of crypting code in Infozip distribution - - The encryption/decryption parts of this source code (as opposed to the - non-echoing password parts) were originally written in Europe. The - whole source package can be freely distributed, including from the USA. - (Prior to January 2000, re-export from the US was a violation of US law.) - - This encryption code is a direct transcription of the algorithm from - Roger Schlafly, described by Phil Katz in the file appnote.txt. This - file (appnote.txt) is distributed with the PKZIP program (even in the - version without encryption capabilities). - - If you don't need crypting in your application, just define symbols - NOCRYPT and NOUNCRYPT. - - This code support the "Traditional PKWARE Encryption". - - The new AES encryption added on Zip format by Winzip (see the page - http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong - Encryption is not supported. -*/ - -#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) - -/*********************************************************************** - * Return the next byte in the pseudo-random sequence - */ -static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) -{ - unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an - * unpredictable manner on 16-bit systems; not a problem - * with any known compiler so far, though */ - - temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; - return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); -} - -/*********************************************************************** - * Update the encryption keys with the next byte of plain text - */ -static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) -{ - (*(pkeys+0)) = CRC32((*(pkeys+0)), c); - (*(pkeys+1)) += (*(pkeys+0)) & 0xff; - (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; - { - register int keyshift = (int)((*(pkeys+1)) >> 24); - (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); - } - return c; -} - - -/*********************************************************************** - * Initialize the encryption keys and the random header according to - * the given password. - */ -static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) -{ - *(pkeys+0) = 305419896L; - *(pkeys+1) = 591751049L; - *(pkeys+2) = 878082192L; - while (*passwd != '\0') { - update_keys(pkeys,pcrc_32_tab,(int)*passwd); - passwd++; - } -} - -#define zdecode(pkeys,pcrc_32_tab,c) \ - (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) - -#define zencode(pkeys,pcrc_32_tab,c,t) \ - (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) - -#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED - -#define RAND_HEAD_LEN 12 - /* "last resort" source for second part of crypt seed pattern */ -# ifndef ZCR_SEED2 -# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ -# endif - -static int crypthead(const char* passwd, /* password string */ - unsigned char* buf, /* where to write header */ - int bufSize, - unsigned long* pkeys, - const z_crc_t* pcrc_32_tab, - unsigned long crcForCrypting) -{ - int n; /* index in random header */ - int t; /* temporary */ - int c; /* random byte */ - unsigned char header[RAND_HEAD_LEN-2]; /* random header */ - static unsigned calls = 0; /* ensure different random header each time */ - - if (bufSize> 7) & 0xff; - header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); - } - /* Encrypt random header (last two bytes is high word of crc) */ - init_keys(passwd, pkeys, pcrc_32_tab); - for (n = 0; n < RAND_HEAD_LEN-2; n++) - { - buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); - } - buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); - buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); - return n; -} - -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.c orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.c --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.c 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,247 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - -*/ - -#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) - #define _CRT_SECURE_NO_WARNINGS -#endif - -#if defined(__APPLE__) || defined(IOAPI_NO_64) -// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions -#define FOPEN_FUNC(filename, mode) fopen(filename, mode) -#define FTELLO_FUNC(stream) ftello(stream) -#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) -#else -#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) -#define FTELLO_FUNC(stream) ftello64(stream) -#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) -#endif - - -#include "ioapi.h" - -voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) -{ - if (pfilefunc->zfile_func64.zopen64_file != NULL) - return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); - else - { - return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); - } -} - -long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) -{ - if (pfilefunc->zfile_func64.zseek64_file != NULL) - return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); - else - { - uLong offsetTruncated = (uLong)offset; - if (offsetTruncated != offset) - return -1; - else - return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); - } -} - -ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) -{ - if (pfilefunc->zfile_func64.zseek64_file != NULL) - return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); - else - { - uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); - if ((tell_uLong) == MAXU32) - return (ZPOS64_T)-1; - else - return tell_uLong; - } -} - -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) -{ - p_filefunc64_32->zfile_func64.zopen64_file = NULL; - p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; - p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; - p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; - p_filefunc64_32->zfile_func64.ztell64_file = NULL; - p_filefunc64_32->zfile_func64.zseek64_file = NULL; - p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; - p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; - p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; - p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; - p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; -} - - - -static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); -static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); -static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); -static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); -static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); - -static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename!=NULL) && (mode_fopen != NULL)) - file = fopen(filename, mode_fopen); - return file; -} - -static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) -{ - FILE* file = NULL; - const char* mode_fopen = NULL; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) - mode_fopen = "rb"; - else - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) - mode_fopen = "r+b"; - else - if (mode & ZLIB_FILEFUNC_MODE_CREATE) - mode_fopen = "wb"; - - if ((filename!=NULL) && (mode_fopen != NULL)) - file = FOPEN_FUNC((const char*)filename, mode_fopen); - return file; -} - - -static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) -{ - uLong ret; - ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); - return ret; -} - -static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) -{ - uLong ret; - ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); - return ret; -} - -static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) -{ - long ret; - ret = ftell((FILE *)stream); - return ret; -} - - -static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) -{ - ZPOS64_T ret; - ret = FTELLO_FUNC((FILE *)stream); - return ret; -} - -static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) -{ - int fseek_origin=0; - long ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END : - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - fseek_origin = SEEK_SET; - break; - default: return -1; - } - ret = 0; - if (fseek((FILE *)stream, offset, fseek_origin) != 0) - ret = -1; - return ret; -} - -static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) -{ - int fseek_origin=0; - long ret; - switch (origin) - { - case ZLIB_FILEFUNC_SEEK_CUR : - fseek_origin = SEEK_CUR; - break; - case ZLIB_FILEFUNC_SEEK_END : - fseek_origin = SEEK_END; - break; - case ZLIB_FILEFUNC_SEEK_SET : - fseek_origin = SEEK_SET; - break; - default: return -1; - } - ret = 0; - - if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) - ret = -1; - - return ret; -} - - -static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) -{ - int ret; - ret = fclose((FILE *)stream); - return ret; -} - -static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) -{ - int ret; - ret = ferror((FILE *)stream); - return ret; -} - -void fill_fopen_filefunc (pzlib_filefunc_def) - zlib_filefunc_def* pzlib_filefunc_def; -{ - pzlib_filefunc_def->zopen_file = fopen_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell_file = ftell_file_func; - pzlib_filefunc_def->zseek_file = fseek_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} - -void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = fopen64_file_func; - pzlib_filefunc_def->zread_file = fread_file_func; - pzlib_filefunc_def->zwrite_file = fwrite_file_func; - pzlib_filefunc_def->ztell64_file = ftell64_file_func; - pzlib_filefunc_def->zseek64_file = fseek64_file_func; - pzlib_filefunc_def->zclose_file = fclose_file_func; - pzlib_filefunc_def->zerror_file = ferror_file_func; - pzlib_filefunc_def->opaque = NULL; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/ioapi.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,208 +0,0 @@ -/* ioapi.h -- IO base function header for compress/uncompress .zip - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - Changes - - Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) - Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. - More if/def section may be needed to support other platforms - Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. - (but you should use iowin32.c for windows instead) - -*/ - -#ifndef _ZLIBIOAPI64_H -#define _ZLIBIOAPI64_H - -#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) - - // Linux needs this to support file operation on files larger then 4+GB - // But might need better if/def to select just the platforms that needs them. - - #ifndef __USE_FILE_OFFSET64 - #define __USE_FILE_OFFSET64 - #endif - #ifndef __USE_LARGEFILE64 - #define __USE_LARGEFILE64 - #endif - #ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE - #endif - #ifndef _FILE_OFFSET_BIT - #define _FILE_OFFSET_BIT 64 - #endif - -#endif - -#include -#include -#include "zlib.h" - -#if defined(USE_FILE32API) -#define fopen64 fopen -#define ftello64 ftell -#define fseeko64 fseek -#else -#ifdef __FreeBSD__ -#define fopen64 fopen -#define ftello64 ftello -#define fseeko64 fseeko -#endif -#ifdef _MSC_VER - #define fopen64 fopen - #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) - #define ftello64 _ftelli64 - #define fseeko64 _fseeki64 - #else // old MSC - #define ftello64 ftell - #define fseeko64 fseek - #endif -#endif -#endif - -/* -#ifndef ZPOS64_T - #ifdef _WIN32 - #define ZPOS64_T fpos_t - #else - #include - #define ZPOS64_T uint64_t - #endif -#endif -*/ - -#ifdef HAVE_MINIZIP64_CONF_H -#include "mz64conf.h" -#endif - -/* a type choosen by DEFINE */ -#ifdef HAVE_64BIT_INT_CUSTOM -typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; -#else -#ifdef HAS_STDINT_H -#include "stdint.h" -typedef uint64_t ZPOS64_T; -#else - -/* Maximum unsigned 32-bit value used as placeholder for zip64 */ -#define MAXU32 0xffffffff - -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef unsigned __int64 ZPOS64_T; -#else -typedef unsigned long long int ZPOS64_T; -#endif -#endif -#endif - - - -#ifdef __cplusplus -extern "C" { -#endif - - -#define ZLIB_FILEFUNC_SEEK_CUR (1) -#define ZLIB_FILEFUNC_SEEK_END (2) -#define ZLIB_FILEFUNC_SEEK_SET (0) - -#define ZLIB_FILEFUNC_MODE_READ (1) -#define ZLIB_FILEFUNC_MODE_WRITE (2) -#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) - -#define ZLIB_FILEFUNC_MODE_EXISTING (4) -#define ZLIB_FILEFUNC_MODE_CREATE (8) - - -#ifndef ZCALLBACK - #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) - #define ZCALLBACK CALLBACK - #else - #define ZCALLBACK - #endif -#endif - - - - -typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); -typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); -typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); -typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); -typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); - -typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); - - -/* here is the "old" 32 bits structure structure */ -typedef struct zlib_filefunc_def_s -{ - open_file_func zopen_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell_file_func ztell_file; - seek_file_func zseek_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc_def; - -typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); -typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); -typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); - -typedef struct zlib_filefunc64_def_s -{ - open64_file_func zopen64_file; - read_file_func zread_file; - write_file_func zwrite_file; - tell64_file_func ztell64_file; - seek64_file_func zseek64_file; - close_file_func zclose_file; - testerror_file_func zerror_file; - voidpf opaque; -} zlib_filefunc64_def; - -void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); -void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); - -/* now internal definition, only for zip.c and unzip.h */ -typedef struct zlib_filefunc64_32_def_s -{ - zlib_filefunc64_def zfile_func64; - open_file_func zopen32_file; - tell_file_func ztell32_file; - seek_file_func zseek32_file; -} zlib_filefunc64_32_def; - - -#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) -#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) -//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) -//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) -#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) -#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) - -voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); -long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); -ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); - -void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); - -#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) -#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) -#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) - -#ifdef __cplusplus -} -#endif - -#endif diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/NOTES orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/NOTES --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/NOTES 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/NOTES 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -These files come from the "contrib/minizip" directory in zlib 1.2.11. diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.c orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.c --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.c 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,2007 +0,0 @@ -/* zip.c -- IO on .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - Changes - Oct-2009 - Mathias Svensson - Remove old C style function prototypes - Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives - Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. - Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data - It is used when recreting zip archive with RAW when deleting items from a zip. - ZIP64 data is automatically added to items that needs it, and existing ZIP64 data need to be removed. - Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) - Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer - -*/ - - -#include -#include -#include -#include -#include "zlib.h" -#include "zip.h" - -#ifdef STDC -# include -# include -# include -#endif -#ifdef NO_ERRNO_H - extern int errno; -#else -# include -#endif - - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#ifndef VERSIONMADEBY -# define VERSIONMADEBY (0x0) /* platform depedent */ -#endif - -#ifndef Z_BUFSIZE -#define Z_BUFSIZE (64*1024) //(16384) -#endif - -#ifndef Z_MAXFILENAMEINZIP -#define Z_MAXFILENAMEINZIP (256) -#endif - -#ifndef ALLOC -# define ALLOC(size) (malloc(size)) -#endif -#ifndef TRYFREE -# define TRYFREE(p) {if (p) free(p);} -#endif - -/* -#define SIZECENTRALDIRITEM (0x2e) -#define SIZEZIPLOCALHEADER (0x1e) -*/ - -/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ - - -// NOT sure that this work on ALL platform -#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef DEF_MEM_LEVEL -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -#endif -const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; - - -#define SIZEDATA_INDATABLOCK (4096-(4*4)) - -#define LOCALHEADERMAGIC (0x04034b50) -#define CENTRALHEADERMAGIC (0x02014b50) -#define ENDHEADERMAGIC (0x06054b50) -#define ZIP64ENDHEADERMAGIC (0x6064b50) -#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) - -#define FLAG_LOCALHEADER_OFFSET (0x06) -#define CRC_LOCALHEADER_OFFSET (0x0e) - -#define SIZECENTRALHEADER (0x2e) /* 46 */ - -typedef struct linkedlist_datablock_internal_s -{ - struct linkedlist_datablock_internal_s* next_datablock; - uLong avail_in_this_block; - uLong filled_in_this_block; - uLong unused; /* for future use and alignment */ - unsigned char data[SIZEDATA_INDATABLOCK]; -} linkedlist_datablock_internal; - -typedef struct linkedlist_data_s -{ - linkedlist_datablock_internal* first_block; - linkedlist_datablock_internal* last_block; -} linkedlist_data; - - -typedef struct -{ - z_stream stream; /* zLib stream structure for inflate */ -#ifdef HAVE_BZIP2 - bz_stream bstream; /* bzLib stream structure for bziped */ -#endif - - int stream_initialised; /* 1 is stream is initialised */ - uInt pos_in_buffered_data; /* last written byte in buffered_data */ - - ZPOS64_T pos_local_header; /* offset of the local header of the file - currenty writing */ - char* central_header; /* central header data for the current file */ - uLong size_centralExtra; - uLong size_centralheader; /* size of the central header for cur file */ - uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ - uLong flag; /* flag of the file currently writing */ - - int method; /* compression method of file currenty wr.*/ - int raw; /* 1 for directly writing raw data */ - Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ - uLong dosDate; - uLong crc32; - int encrypt; - int zip64; /* Add ZIP64 extened information in the extra field */ - ZPOS64_T pos_zip64extrainfo; - ZPOS64_T totalCompressedData; - ZPOS64_T totalUncompressedData; -#ifndef NOCRYPT - unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const z_crc_t* pcrc_32_tab; - int crypt_header_size; -#endif -} curfile64_info; - -typedef struct -{ - zlib_filefunc64_32_def z_filefunc; - voidpf filestream; /* io structore of the zipfile */ - linkedlist_data central_dir;/* datablock with central dir in construction*/ - int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ - curfile64_info ci; /* info on the file curretly writing */ - - ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ - ZPOS64_T add_position_when_writing_offset; - ZPOS64_T number_entry; - -#ifndef NO_ADDFILEINEXISTINGZIP - char *globalcomment; -#endif - -} zip64_internal; - - -#ifndef NOCRYPT -#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED -#include "crypt.h" -#endif - -local linkedlist_datablock_internal* allocate_new_datablock() -{ - linkedlist_datablock_internal* ldi; - ldi = (linkedlist_datablock_internal*) - ALLOC(sizeof(linkedlist_datablock_internal)); - if (ldi!=NULL) - { - ldi->next_datablock = NULL ; - ldi->filled_in_this_block = 0 ; - ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; - } - return ldi; -} - -local void free_datablock(linkedlist_datablock_internal* ldi) -{ - while (ldi!=NULL) - { - linkedlist_datablock_internal* ldinext = ldi->next_datablock; - TRYFREE(ldi); - ldi = ldinext; - } -} - -local void init_linkedlist(linkedlist_data* ll) -{ - ll->first_block = ll->last_block = NULL; -} - -local void free_linkedlist(linkedlist_data* ll) -{ - free_datablock(ll->first_block); - ll->first_block = ll->last_block = NULL; -} - - -local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) -{ - linkedlist_datablock_internal* ldi; - const unsigned char* from_copy; - - if (ll==NULL) - return ZIP_INTERNALERROR; - - if (ll->last_block == NULL) - { - ll->first_block = ll->last_block = allocate_new_datablock(); - if (ll->first_block == NULL) - return ZIP_INTERNALERROR; - } - - ldi = ll->last_block; - from_copy = (unsigned char*)buf; - - while (len>0) - { - uInt copy_this; - uInt i; - unsigned char* to_copy; - - if (ldi->avail_in_this_block==0) - { - ldi->next_datablock = allocate_new_datablock(); - if (ldi->next_datablock == NULL) - return ZIP_INTERNALERROR; - ldi = ldi->next_datablock ; - ll->last_block = ldi; - } - - if (ldi->avail_in_this_block < len) - copy_this = (uInt)ldi->avail_in_this_block; - else - copy_this = (uInt)len; - - to_copy = &(ldi->data[ldi->filled_in_this_block]); - - for (i=0;ifilled_in_this_block += copy_this; - ldi->avail_in_this_block -= copy_this; - from_copy += copy_this ; - len -= copy_this; - } - return ZIP_OK; -} - - - -/****************************************************************************/ - -#ifndef NO_ADDFILEINEXISTINGZIP -/* =========================================================================== - Inputs a long in LSB order to the given file - nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) -*/ - -local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); -local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) -{ - unsigned char buf[8]; - int n; - for (n = 0; n < nbByte; n++) - { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - if (x != 0) - { /* data overflow - hack for ZIP64 (X Roche) */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } - - if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) - return ZIP_ERRNO; - else - return ZIP_OK; -} - -local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); -local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) -{ - unsigned char* buf=(unsigned char*)dest; - int n; - for (n = 0; n < nbByte; n++) { - buf[n] = (unsigned char)(x & 0xff); - x >>= 8; - } - - if (x != 0) - { /* data overflow - hack for ZIP64 */ - for (n = 0; n < nbByte; n++) - { - buf[n] = 0xff; - } - } -} - -/****************************************************************************/ - - -local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) -{ - uLong year = (uLong)ptm->tm_year; - if (year>=1980) - year-=1980; - else if (year>=80) - year-=80; - return - (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | - ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); -} - - -/****************************************************************************/ - -local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); - -local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) -{ - unsigned char c; - int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); - if (err==1) - { - *pi = (int)c; - return ZIP_OK; - } - else - { - if (ZERROR64(*pzlib_filefunc_def,filestream)) - return ZIP_ERRNO; - else - return ZIP_EOF; - } -} - - -/* =========================================================================== - Reads a long in LSB order from the given gz_stream. Sets -*/ -local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); - -local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ - uLong x ; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); - -local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) -{ - uLong x ; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (uLong)i; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<8; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<16; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((uLong)i)<<24; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - return err; -} - -local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); - - -local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) -{ - ZPOS64_T x; - int i = 0; - int err; - - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x = (ZPOS64_T)i; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<8; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<16; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<24; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<32; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<40; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<48; - - if (err==ZIP_OK) - err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); - x += ((ZPOS64_T)i)<<56; - - if (err==ZIP_OK) - *pX = x; - else - *pX = 0; - - return err; -} - -#ifndef BUFREADCOMMENT -#define BUFREADCOMMENT (0x400) -#endif -/* - Locate the Central directory of a zipfile (at the end, just before - the global comment) -*/ -local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); - -local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T uSizeFile; - ZPOS64_T uBackRead; - ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; - - if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - - uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); - if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && - ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) - { - uPosFound = uReadPos+i; - break; - } - - if (uPosFound!=0) - break; - } - TRYFREE(buf); - return uPosFound; -} - -/* -Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before -the global comment) -*/ -local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); - -local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) -{ - unsigned char* buf; - ZPOS64_T uSizeFile; - ZPOS64_T uBackRead; - ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ - ZPOS64_T uPosFound=0; - uLong uL; - ZPOS64_T relativeOffset; - - if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) - return 0; - - uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); - - if (uMaxBack>uSizeFile) - uMaxBack = uSizeFile; - - buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); - if (buf==NULL) - return 0; - - uBackRead = 4; - while (uBackReaduMaxBack) - uBackRead = uMaxBack; - else - uBackRead+=BUFREADCOMMENT; - uReadPos = uSizeFile-uBackRead ; - - uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? - (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); - if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) - break; - - if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) - break; - - for (i=(int)uReadSize-3; (i--)>0;) - { - // Signature "0x07064b50" Zip64 end of central directory locater - if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) - { - uPosFound = uReadPos+i; - break; - } - } - - if (uPosFound!=0) - break; - } - - TRYFREE(buf); - if (uPosFound == 0) - return 0; - - /* Zip64 end of central directory locator */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) - return 0; - - /* the signature, already checked */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - - /* number of the disk with the start of the zip64 end of central directory */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - if (uL != 0) - return 0; - - /* relative offset of the zip64 end of central directory record */ - if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) - return 0; - - /* total number of disks */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - if (uL != 1) - return 0; - - /* Goto Zip64 end of central directory record */ - if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) - return 0; - - /* the signature */ - if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) - return 0; - - if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' - return 0; - - return relativeOffset; -} - -int LoadCentralDirectoryRecord(zip64_internal* pziinit) -{ - int err=ZIP_OK; - ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ - - ZPOS64_T size_central_dir; /* size of the central directory */ - ZPOS64_T offset_central_dir; /* offset of start of central directory */ - ZPOS64_T central_pos; - uLong uL; - - uLong number_disk; /* number of the current dist, used for - spaning ZIP, unsupported, always 0*/ - uLong number_disk_with_CD; /* number the the disk with central dir, used - for spaning ZIP, unsupported, always 0*/ - ZPOS64_T number_entry; - ZPOS64_T number_entry_CD; /* total number of entries in - the central dir - (same than number_entry on nospan) */ - uLong VersionMadeBy; - uLong VersionNeeded; - uLong size_comment; - - int hasZIP64Record = 0; - - // check first if we find a ZIP64 record - central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); - if(central_pos > 0) - { - hasZIP64Record = 1; - } - else if(central_pos == 0) - { - central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); - } - -/* disable to allow appending to empty ZIP archive - if (central_pos==0) - err=ZIP_ERRNO; -*/ - - if(hasZIP64Record) - { - ZPOS64_T sizeEndOfCentralDirectory; - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* size of zip64 end of central directory record */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) - err=ZIP_ERRNO; - - /* version made by */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) - err=ZIP_ERRNO; - - /* version needed to extract */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central directory on this disk */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central directory */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - /* offset of start of central directory with respect to the - starting disk number */ - if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) - err=ZIP_ERRNO; - - // TODO.. - // read the comment from the standard central header. - size_comment = 0; - } - else - { - // Read End of central Directory info - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) - err=ZIP_ERRNO; - - /* the signature, already checked */ - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of this disk */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) - err=ZIP_ERRNO; - - /* number of the disk with the start of the central directory */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) - err=ZIP_ERRNO; - - /* total number of entries in the central dir on this disk */ - number_entry = 0; - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - number_entry = uL; - - /* total number of entries in the central dir */ - number_entry_CD = 0; - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - number_entry_CD = uL; - - if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) - err=ZIP_BADZIPFILE; - - /* size of the central directory */ - size_central_dir = 0; - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - size_central_dir = uL; - - /* offset of start of central directory with respect to the starting disk number */ - offset_central_dir = 0; - if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) - err=ZIP_ERRNO; - else - offset_central_dir = uL; - - - /* zipfile global comment length */ - if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) - err=ZIP_ERRNO; - } - - if ((central_posz_filefunc, pziinit->filestream); - return ZIP_ERRNO; - } - - if (size_comment>0) - { - pziinit->globalcomment = (char*)ALLOC(size_comment+1); - if (pziinit->globalcomment) - { - size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); - pziinit->globalcomment[size_comment]=0; - } - } - - byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); - pziinit->add_position_when_writing_offset = byte_before_the_zipfile; - - { - ZPOS64_T size_central_dir_to_read = size_central_dir; - size_t buf_size = SIZEDATA_INDATABLOCK; - void* buf_read = (void*)ALLOC(buf_size); - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - while ((size_central_dir_to_read>0) && (err==ZIP_OK)) - { - ZPOS64_T read_this = SIZEDATA_INDATABLOCK; - if (read_this > size_central_dir_to_read) - read_this = size_central_dir_to_read; - - if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) - err=ZIP_ERRNO; - - if (err==ZIP_OK) - err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); - - size_central_dir_to_read-=read_this; - } - TRYFREE(buf_read); - } - pziinit->begin_pos = byte_before_the_zipfile; - pziinit->number_entry = number_entry_CD; - - if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) - err=ZIP_ERRNO; - - return err; -} - - -#endif /* !NO_ADDFILEINEXISTINGZIP*/ - - -/************************************************************/ -extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) -{ - zip64_internal ziinit; - zip64_internal* zi; - int err=ZIP_OK; - - ziinit.z_filefunc.zseek32_file = NULL; - ziinit.z_filefunc.ztell32_file = NULL; - if (pzlib_filefunc64_32_def==NULL) - fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); - else - ziinit.z_filefunc = *pzlib_filefunc64_32_def; - - ziinit.filestream = ZOPEN64(ziinit.z_filefunc, - pathname, - (append == APPEND_STATUS_CREATE) ? - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : - (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); - - if (ziinit.filestream == NULL) - return NULL; - - if (append == APPEND_STATUS_CREATEAFTER) - ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); - - ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); - ziinit.in_opened_file_inzip = 0; - ziinit.ci.stream_initialised = 0; - ziinit.number_entry = 0; - ziinit.add_position_when_writing_offset = 0; - init_linkedlist(&(ziinit.central_dir)); - - - - zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); - if (zi==NULL) - { - ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); - return NULL; - } - - /* now we add file in a zipfile */ -# ifndef NO_ADDFILEINEXISTINGZIP - ziinit.globalcomment = NULL; - if (append == APPEND_STATUS_ADDINZIP) - { - // Read and Cache Central Directory Records - err = LoadCentralDirectoryRecord(&ziinit); - } - - if (globalcomment) - { - *globalcomment = ziinit.globalcomment; - } -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - - if (err != ZIP_OK) - { -# ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(ziinit.globalcomment); -# endif /* !NO_ADDFILEINEXISTINGZIP*/ - TRYFREE(zi); - return NULL; - } - else - { - *zi = ziinit; - return (zipFile)zi; - } -} - -extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) -{ - if (pzlib_filefunc32_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); - return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); - } - else - return zipOpen3(pathname, append, globalcomment, NULL); -} - -extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) -{ - if (pzlib_filefunc_def != NULL) - { - zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; - zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; - zlib_filefunc64_32_def_fill.ztell32_file = NULL; - zlib_filefunc64_32_def_fill.zseek32_file = NULL; - return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); - } - else - return zipOpen3(pathname, append, globalcomment, NULL); -} - - - -extern zipFile ZEXPORT zipOpen (const char* pathname, int append) -{ - return zipOpen3((const void*)pathname,append,NULL,NULL); -} - -extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) -{ - return zipOpen3(pathname,append,NULL,NULL); -} - -int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) -{ - /* write the local header */ - int err; - uInt size_filename = (uInt)strlen(filename); - uInt size_extrafield = size_extrafield_local; - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); - - if (err==ZIP_OK) - { - if(zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ - } - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); - - // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ - if (err==ZIP_OK) - { - if(zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ - } - if (err==ZIP_OK) - { - if(zi->ci.zip64) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ - } - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); - - if(zi->ci.zip64) - { - size_extrafield += 20; - } - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); - - if ((err==ZIP_OK) && (size_filename > 0)) - { - if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) - err = ZIP_ERRNO; - } - - if ((err==ZIP_OK) && (size_extrafield_local > 0)) - { - if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) - err = ZIP_ERRNO; - } - - - if ((err==ZIP_OK) && (zi->ci.zip64)) - { - // write the Zip64 extended info - short HeaderID = 1; - short DataSize = 16; - ZPOS64_T CompressedSize = 0; - ZPOS64_T UncompressedSize = 0; - - // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) - zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); - - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); - } - - return err; -} - -/* - NOTE. - When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped - before calling this function it can be done with zipRemoveExtraInfoBlock - - It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize - unnecessary allocations. - */ -extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, - uLong versionMadeBy, uLong flagBase, int zip64) -{ - zip64_internal* zi; - uInt size_filename; - uInt size_comment; - uInt i; - int err = ZIP_OK; - -# ifdef NOCRYPT - (crcForCrypting); - if (password != NULL) - return ZIP_PARAMERROR; -# endif - - if (file == NULL) - return ZIP_PARAMERROR; - -#ifdef HAVE_BZIP2 - if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) - return ZIP_PARAMERROR; -#else - if ((method!=0) && (method!=Z_DEFLATED)) - return ZIP_PARAMERROR; -#endif - - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - if (err != ZIP_OK) - return err; - } - - if (filename==NULL) - filename="-"; - - if (comment==NULL) - size_comment = 0; - else - size_comment = (uInt)strlen(comment); - - size_filename = (uInt)strlen(filename); - - if (zipfi == NULL) - zi->ci.dosDate = 0; - else - { - if (zipfi->dosDate != 0) - zi->ci.dosDate = zipfi->dosDate; - else - zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); - } - - zi->ci.flag = flagBase; - if ((level==8) || (level==9)) - zi->ci.flag |= 2; - if (level==2) - zi->ci.flag |= 4; - if (level==1) - zi->ci.flag |= 6; - if (password != NULL) - zi->ci.flag |= 1; - - zi->ci.crc32 = 0; - zi->ci.method = method; - zi->ci.encrypt = 0; - zi->ci.stream_initialised = 0; - zi->ci.pos_in_buffered_data = 0; - zi->ci.raw = raw; - zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); - - zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; - zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data - - zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); - - zi->ci.size_centralExtra = size_extrafield_global; - zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); - /* version info */ - zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); - zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); - zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); - zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); - zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); - zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ - zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ - zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ - zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); - zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); - zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); - zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ - - if (zipfi==NULL) - zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); - else - zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); - - if (zipfi==NULL) - zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); - else - zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); - - if(zi->ci.pos_local_header >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); - else - zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writing_offset,4); - - for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = - *(((const char*)extrafield_global)+i); - - for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ - size_extrafield_global+i) = *(comment+i); - if (zi->ci.central_header == NULL) - return ZIP_INTERNALERROR; - - zi->ci.zip64 = zip64; - zi->ci.totalCompressedData = 0; - zi->ci.totalUncompressedData = 0; - zi->ci.pos_zip64extrainfo = 0; - - err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); - -#ifdef HAVE_BZIP2 - zi->ci.bstream.avail_in = (uInt)0; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - zi->ci.bstream.total_in_hi32 = 0; - zi->ci.bstream.total_in_lo32 = 0; - zi->ci.bstream.total_out_hi32 = 0; - zi->ci.bstream.total_out_lo32 = 0; -#endif - - zi->ci.stream.avail_in = (uInt)0; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - zi->ci.stream.total_in = 0; - zi->ci.stream.total_out = 0; - zi->ci.stream.data_type = Z_BINARY; - -#ifdef HAVE_BZIP2 - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) -#else - if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) -#endif - { - if(zi->ci.method == Z_DEFLATED) - { - zi->ci.stream.zalloc = (alloc_func)0; - zi->ci.stream.zfree = (free_func)0; - zi->ci.stream.opaque = (voidpf)0; - - if (windowBits>0) - windowBits = -windowBits; - - err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); - - if (err==Z_OK) - zi->ci.stream_initialised = Z_DEFLATED; - } - else if(zi->ci.method == Z_BZIP2ED) - { -#ifdef HAVE_BZIP2 - // Init BZip stuff here - zi->ci.bstream.bzalloc = 0; - zi->ci.bstream.bzfree = 0; - zi->ci.bstream.opaque = (voidpf)0; - - err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); - if(err == BZ_OK) - zi->ci.stream_initialised = Z_BZIP2ED; -#endif - } - - } - -# ifndef NOCRYPT - zi->ci.crypt_header_size = 0; - if ((err==Z_OK) && (password != NULL)) - { - unsigned char bufHead[RAND_HEAD_LEN]; - unsigned int sizeHead; - zi->ci.encrypt = 1; - zi->ci.pcrc_32_tab = get_crc_table(); - /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ - - sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); - zi->ci.crypt_header_size = sizeHead; - - if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) - err = ZIP_ERRNO; - } -# endif - - if (err==Z_OK) - zi->in_opened_file_inzip = 1; - return err; -} - -extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, - uLong versionMadeBy, uLong flagBase) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, versionMadeBy, flagBase, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, - int windowBits,int memLevel, int strategy, - const char* password, uLong crcForCrypting, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - windowBits, memLevel, strategy, - password, crcForCrypting, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, 0); -} - -extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void* extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int raw, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, raw, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void*extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level, int zip64) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, zip64); -} - -extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, - const void* extrafield_local, uInt size_extrafield_local, - const void*extrafield_global, uInt size_extrafield_global, - const char* comment, int method, int level) -{ - return zipOpenNewFileInZip4_64 (file, filename, zipfi, - extrafield_local, size_extrafield_local, - extrafield_global, size_extrafield_global, - comment, method, level, 0, - -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, - NULL, 0, VERSIONMADEBY, 0, 0); -} - -local int zip64FlushWriteBuffer(zip64_internal* zi) -{ - int err=ZIP_OK; - - if (zi->ci.encrypt != 0) - { -#ifndef NOCRYPT - uInt i; - int t; - for (i=0;ici.pos_in_buffered_data;i++) - zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); -#endif - } - - if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) - err = ZIP_ERRNO; - - zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; - -#ifdef HAVE_BZIP2 - if(zi->ci.method == Z_BZIP2ED) - { - zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; - zi->ci.bstream.total_in_lo32 = 0; - zi->ci.bstream.total_in_hi32 = 0; - } - else -#endif - { - zi->ci.totalUncompressedData += zi->ci.stream.total_in; - zi->ci.stream.total_in = 0; - } - - - zi->ci.pos_in_buffered_data = 0; - - return err; -} - -extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) -{ - zip64_internal* zi; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - - zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); - -#ifdef HAVE_BZIP2 - if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) - { - zi->ci.bstream.next_in = (void*)buf; - zi->ci.bstream.avail_in = len; - err = BZ_RUN_OK; - - while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) - { - if (zi->ci.bstream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - } - - - if(err != BZ_RUN_OK) - break; - - if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; -// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; - err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; - } - } - - if(err == BZ_RUN_OK) - err = ZIP_OK; - } - else -#endif - { - zi->ci.stream.next_in = (Bytef*)buf; - zi->ci.stream.avail_in = len; - - while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) - { - if (zi->ci.stream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - - - if(err != ZIP_OK) - break; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - uLong uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_NO_FLUSH); - if(uTotalOutBefore > zi->ci.stream.total_out) - { - int bBreak = 0; - bBreak++; - } - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - else - { - uInt copy_this,i; - if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) - copy_this = zi->ci.stream.avail_in; - else - copy_this = zi->ci.stream.avail_out; - - for (i = 0; i < copy_this; i++) - *(((char*)zi->ci.stream.next_out)+i) = - *(((const char*)zi->ci.stream.next_in)+i); - { - zi->ci.stream.avail_in -= copy_this; - zi->ci.stream.avail_out-= copy_this; - zi->ci.stream.next_in+= copy_this; - zi->ci.stream.next_out+= copy_this; - zi->ci.stream.total_in+= copy_this; - zi->ci.stream.total_out+= copy_this; - zi->ci.pos_in_buffered_data += copy_this; - } - } - }// while(...) - } - - return err; -} - -extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) -{ - return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); -} - -extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) -{ - zip64_internal* zi; - ZPOS64_T compressed_size; - uLong invalidValue = 0xffffffff; - short datasize = 0; - int err=ZIP_OK; - - if (file == NULL) - return ZIP_PARAMERROR; - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 0) - return ZIP_PARAMERROR; - zi->ci.stream.avail_in = 0; - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - while (err==ZIP_OK) - { - uLong uTotalOutBefore; - if (zi->ci.stream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.stream.next_out = zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.stream.total_out; - err=deflate(&zi->ci.stream, Z_FINISH); - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; - } - } - else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) - { -#ifdef HAVE_BZIP2 - err = BZ_FINISH_OK; - while (err==BZ_FINISH_OK) - { - uLong uTotalOutBefore; - if (zi->ci.bstream.avail_out == 0) - { - if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) - err = ZIP_ERRNO; - zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; - zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; - } - uTotalOutBefore = zi->ci.bstream.total_out_lo32; - err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); - if(err == BZ_STREAM_END) - err = Z_STREAM_END; - - zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); - } - - if(err == BZ_FINISH_OK) - err = ZIP_OK; -#endif - } - - if (err==Z_STREAM_END) - err=ZIP_OK; /* this is normal */ - - if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) - { - if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) - err = ZIP_ERRNO; - } - - if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) - { - int tmp_err = deflateEnd(&zi->ci.stream); - if (err == ZIP_OK) - err = tmp_err; - zi->ci.stream_initialised = 0; - } -#ifdef HAVE_BZIP2 - else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) - { - int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); - if (err==ZIP_OK) - err = tmperr; - zi->ci.stream_initialised = 0; - } -#endif - - if (!zi->ci.raw) - { - crc32 = (uLong)zi->ci.crc32; - uncompressed_size = zi->ci.totalUncompressedData; - } - compressed_size = zi->ci.totalCompressedData; - -# ifndef NOCRYPT - compressed_size += zi->ci.crypt_header_size; -# endif - - // update Current Item crc and sizes, - if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) - { - /*version Made by*/ - zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); - /*version needed*/ - zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); - - } - - zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ - - - if(compressed_size >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ - else - zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ - - /// set internal file attributes field - if (zi->ci.stream.data_type == Z_ASCII) - zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); - - if(uncompressed_size >= 0xffffffff) - zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ - else - zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ - - // Add ZIP64 extra info field for uncompressed size - if(uncompressed_size >= 0xffffffff) - datasize += 8; - - // Add ZIP64 extra info field for compressed size - if(compressed_size >= 0xffffffff) - datasize += 8; - - // Add ZIP64 extra info field for relative offset to local file header of current file - if(zi->ci.pos_local_header >= 0xffffffff) - datasize += 8; - - if(datasize > 0) - { - char* p = NULL; - - if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) - { - // we can not write more data to the buffer that we have room for. - return ZIP_BADZIPFILE; - } - - p = zi->ci.central_header + zi->ci.size_centralheader; - - // Add Extra Information Header for 'ZIP64 information' - zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID - p += 2; - zip64local_putValue_inmemory(p, datasize, 2); // DataSize - p += 2; - - if(uncompressed_size >= 0xffffffff) - { - zip64local_putValue_inmemory(p, uncompressed_size, 8); - p += 8; - } - - if(compressed_size >= 0xffffffff) - { - zip64local_putValue_inmemory(p, compressed_size, 8); - p += 8; - } - - if(zi->ci.pos_local_header >= 0xffffffff) - { - zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); - p += 8; - } - - // Update how much extra free space we got in the memory buffer - // and increase the centralheader size so the new ZIP64 fields are included - // ( 4 below is the size of HeaderID and DataSize field ) - zi->ci.size_centralExtraFree -= datasize + 4; - zi->ci.size_centralheader += datasize + 4; - - // Update the extra info size field - zi->ci.size_centralExtra += datasize + 4; - zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); - } - - if (err==ZIP_OK) - err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); - - free(zi->ci.central_header); - - if (err==ZIP_OK) - { - // Update the LocalFileHeader with the new values. - - ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); - - if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ - - if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) - { - if(zi->ci.pos_zip64extrainfo > 0) - { - // Update the size in the ZIP64 extended field. - if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - - if (err==ZIP_OK) /* compressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); - } - else - err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal - } - else - { - if (err==ZIP_OK) /* compressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); - - if (err==ZIP_OK) /* uncompressed size, unknown */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); - } - - if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) - err = ZIP_ERRNO; - } - - zi->number_entry ++; - zi->in_opened_file_inzip = 0; - - return err; -} - -extern int ZEXPORT zipCloseFileInZip (zipFile file) -{ - return zipCloseFileInZipRaw (file,0,0); -} - -int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) -{ - int err = ZIP_OK; - ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writing_offset; - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); - - /*num disks*/ - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); - - /*relative offset*/ - if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); - - /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); - - return err; -} - -int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) -{ - int err = ZIP_OK; - - uLong Zip64DataSize = 44; - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? - - if (err==ZIP_OK) /* version made by */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); - - if (err==ZIP_OK) /* version needed */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); - - if (err==ZIP_OK) /* number of this disk */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); - - if (err==ZIP_OK) /* total number of entries in the central dir */ - err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); - - if (err==ZIP_OK) /* size of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ - { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); - } - return err; -} -int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) -{ - int err = ZIP_OK; - - /*signature*/ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); - - if (err==ZIP_OK) /* number of this disk */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* number of the disk with the start of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); - - if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ - { - { - if(zi->number_entry >= 0xFFFF) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - } - } - - if (err==ZIP_OK) /* total number of entries in the central dir */ - { - if(zi->number_entry >= 0xFFFF) - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); - } - - if (err==ZIP_OK) /* size of the central directory */ - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); - - if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ - { - ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; - if(pos >= 0xffffffff) - { - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); - } - else - err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writing_offset),4); - } - - return err; -} - -int Write_GlobalComment(zip64_internal* zi, const char* global_comment) -{ - int err = ZIP_OK; - uInt size_global_comment = 0; - - if(global_comment != NULL) - size_global_comment = (uInt)strlen(global_comment); - - err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); - - if (err == ZIP_OK && size_global_comment > 0) - { - if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) - err = ZIP_ERRNO; - } - return err; -} - -extern int ZEXPORT zipClose (zipFile file, const char* global_comment) -{ - zip64_internal* zi; - int err = 0; - uLong size_centraldir = 0; - ZPOS64_T centraldir_pos_inzip; - ZPOS64_T pos; - - if (file == NULL) - return ZIP_PARAMERROR; - - zi = (zip64_internal*)file; - - if (zi->in_opened_file_inzip == 1) - { - err = zipCloseFileInZip (file); - } - -#ifndef NO_ADDFILEINEXISTINGZIP - if (global_comment==NULL) - global_comment = zi->globalcomment; -#endif - - centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); - - if (err==ZIP_OK) - { - linkedlist_datablock_internal* ldi = zi->central_dir.first_block; - while (ldi!=NULL) - { - if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) - { - if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) - err = ZIP_ERRNO; - } - - size_centraldir += ldi->filled_in_this_block; - ldi = ldi->next_datablock; - } - } - free_linkedlist(&(zi->central_dir)); - - pos = centraldir_pos_inzip - zi->add_position_when_writing_offset; - if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) - { - ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); - Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); - - Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); - } - - if (err==ZIP_OK) - err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); - - if(err == ZIP_OK) - err = Write_GlobalComment(zi, global_comment); - - if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) - if (err == ZIP_OK) - err = ZIP_ERRNO; - -#ifndef NO_ADDFILEINEXISTINGZIP - TRYFREE(zi->globalcomment); -#endif - TRYFREE(zi); - - return err; -} - -extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) -{ - char* p = pData; - int size = 0; - char* pNewHeader; - char* pTmp; - short header; - short dataSize; - - int retVal = ZIP_OK; - - if(pData == NULL || *dataLen < 4) - return ZIP_PARAMERROR; - - pNewHeader = (char*)ALLOC(*dataLen); - pTmp = pNewHeader; - - while(p < (pData + *dataLen)) - { - header = *(short*)p; - dataSize = *(((short*)p)+1); - - if( header == sHeader ) // Header found. - { - p += dataSize + 4; // skip it. do not copy to temp buffer - } - else - { - // Extra Info block should not be removed, So copy it to the temp buffer. - memcpy(pTmp, p, dataSize + 4); - p += dataSize + 4; - size += dataSize + 4; - } - - } - - if(size < *dataLen) - { - // clean old extra info block. - memset(pData,0, *dataLen); - - // copy the new extra info block over the old - if(size > 0) - memcpy(pData, pNewHeader, size); - - // set the new extra info size - *dataLen = size; - - retVal = ZIP_OK; - } - else - retVal = ZIP_ERRNO; - - TRYFREE(pNewHeader); - - return retVal; -} diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.h orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.h --- orthanc-mysql-2.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.h 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/Orthanc-1.7.0/Resources/ThirdParty/minizip/zip.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,362 +0,0 @@ -/* zip.h -- IO on .zip files using zlib - Version 1.1, February 14h, 2010 - part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) - - Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) - - Modifications for Zip64 support - Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) - - For more info read MiniZip_info.txt - - --------------------------------------------------------------------------- - - Condition of use and distribution are the same than zlib : - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - --------------------------------------------------------------------------- - - Changes - - See header of zip.h - -*/ - -#ifndef _zip12_H -#define _zip12_H - -#ifdef __cplusplus -extern "C" { -#endif - -//#define HAVE_BZIP2 - -#ifndef _ZLIB_H -#include "zlib.h" -#endif - -#ifndef _ZLIBIOAPI_H -#include "ioapi.h" -#endif - -#ifdef HAVE_BZIP2 -#include "bzlib.h" -#endif - -#define Z_BZIP2ED 12 - -#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagzipFile__ { int unused; } zipFile__; -typedef zipFile__ *zipFile; -#else -typedef voidp zipFile; -#endif - -#define ZIP_OK (0) -#define ZIP_EOF (0) -#define ZIP_ERRNO (Z_ERRNO) -#define ZIP_PARAMERROR (-102) -#define ZIP_BADZIPFILE (-103) -#define ZIP_INTERNALERROR (-104) - -#ifndef DEF_MEM_LEVEL -# if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -# else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -# endif -#endif -/* default memLevel */ - -/* tm_zip contain date/time info */ -typedef struct tm_zip_s -{ - uInt tm_sec; /* seconds after the minute - [0,59] */ - uInt tm_min; /* minutes after the hour - [0,59] */ - uInt tm_hour; /* hours since midnight - [0,23] */ - uInt tm_mday; /* day of the month - [1,31] */ - uInt tm_mon; /* months since January - [0,11] */ - uInt tm_year; /* years - [1980..2044] */ -} tm_zip; - -typedef struct -{ - tm_zip tmz_date; /* date in understandable format */ - uLong dosDate; /* if dos_date == 0, tmu_date is used */ -/* uLong flag; */ /* general purpose bit flag 2 bytes */ - - uLong internal_fa; /* internal file attributes 2 bytes */ - uLong external_fa; /* external file attributes 4 bytes */ -} zip_fileinfo; - -typedef const char* zipcharpc; - - -#define APPEND_STATUS_CREATE (0) -#define APPEND_STATUS_CREATEAFTER (1) -#define APPEND_STATUS_ADDINZIP (2) - -extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); -extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); -/* - Create a zipfile. - pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on - an Unix computer "zlib/zlib113.zip". - if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip - will be created at the end of the file. - (useful if the file contain a self extractor code) - if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will - add files in existing zip (be sure you don't add file that doesn't exist) - If the zipfile cannot be opened, the return value is NULL. - Else, the return value is a zipFile Handle, usable with other function - of this zip package. -*/ - -/* Note : there is no delete function into a zipfile. - If you want delete file into a zipfile, you must open a zipfile, and create another - Of couse, you can use RAW reading and writing to copy the file you did not want delte -*/ - -extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, - int append, - zipcharpc* globalcomment, - zlib_filefunc_def* pzlib_filefunc_def)); - -extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, - int append, - zipcharpc* globalcomment, - zlib_filefunc64_def* pzlib_filefunc_def)); - -extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level)); - -extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int zip64)); - -/* - Open a file in the ZIP for writing. - filename : the filename in zip (if NULL, '-' without quote will be used - *zipfi contain supplemental information - if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local - contains the extrafield data the the local header - if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global - contains the extrafield data the the local header - if comment != NULL, comment contain the comment string - method contain the compression method (0 for store, Z_DEFLATED for deflate) - level contain the level of compression (can be Z_DEFAULT_COMPRESSION) - zip64 is set to 1 if a zip64 extended information block should be added to the local file header. - this MUST be '1' if the uncompressed size is >= 0xffffffff. - -*/ - - -extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw)); - - -extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int zip64)); -/* - Same than zipOpenNewFileInZip, except if raw=1, we write raw file - */ - -extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting)); - -extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - int zip64 - )); - -/* - Same than zipOpenNewFileInZip2, except - windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 - password : crypting password (NULL for no crypting) - crcForCrypting : crc of file to compress (needed for crypting) - */ - -extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - uLong versionMadeBy, - uLong flagBase - )); - - -extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, - const char* filename, - const zip_fileinfo* zipfi, - const void* extrafield_local, - uInt size_extrafield_local, - const void* extrafield_global, - uInt size_extrafield_global, - const char* comment, - int method, - int level, - int raw, - int windowBits, - int memLevel, - int strategy, - const char* password, - uLong crcForCrypting, - uLong versionMadeBy, - uLong flagBase, - int zip64 - )); -/* - Same than zipOpenNewFileInZip4, except - versionMadeBy : value for Version made by field - flag : value for flag field (compression level info will be added) - */ - - -extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, - const void* buf, - unsigned len)); -/* - Write data in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); -/* - Close the current file in the zipfile -*/ - -extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, - uLong uncompressed_size, - uLong crc32)); - -extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, - ZPOS64_T uncompressed_size, - uLong crc32)); - -/* - Close the current file in the zipfile, for file opened with - parameter raw=1 in zipOpenNewFileInZip2 - uncompressed_size and crc32 are value for the uncompressed size -*/ - -extern int ZEXPORT zipClose OF((zipFile file, - const char* global_comment)); -/* - Close the zipfile -*/ - - -extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); -/* - zipRemoveExtraInfoBlock - Added by Mathias Svensson - - Remove extra information block from a extra information data for the local file header or central directory header - - It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. - - 0x0001 is the signature header for the ZIP64 extra information blocks - - usage. - Remove ZIP64 Extra information from a central director extra field data - zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); - - Remove ZIP64 Extra information from a Local File Header extra field data - zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* _zip64_H */ diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/populate.sh orthanc-mysql-3.0/debian/orthanc-framework/populate.sh --- orthanc-mysql-2.0/debian/orthanc-framework/populate.sh 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/populate.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -#!/bin/bash - -set -ex - -# Parameters of the Orthanc framework -ORTHANC_MD5=ce5f689e852b01d3672bd3d2f952a5ef -ORTHANC_VERSION=1.7.0 -ORTHANC_FILENAME=Orthanc-${ORTHANC_VERSION} - -# Determine the absolute path to the directory containing the script -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" - -# Download the Orthanc framework -curl http://orthanc.osimis.io/ThirdPartyDownloads/orthanc-framework/${ORTHANC_FILENAME}.tar.gz > /tmp/${ORTHANC_FILENAME}.tar.gz - -# Verify the download -ACTUAL_MD5=`md5sum /tmp/${ORTHANC_FILENAME}.tar.gz | cut -d ' ' -f 1` -if [ "${ACTUAL_MD5}" != "${ORTHANC_MD5}" ]; then - echo "Bad MD5 checksum" - exit -1 -fi - -# Uncompress the Orthanc framework -( cd /tmp ; rm -rf /tmp/${ORTHANC_FILENAME} && tar xvf /tmp/${ORTHANC_FILENAME}.tar.gz ) - -# Possibly remove the files copied from another invocation of this script -rm -rf ${DIR}/${ORTHANC_FILENAME} - - -# Copy the required files from the Orthanc framework next to this script -SOURCE=/tmp/${ORTHANC_FILENAME} -TARGET=${DIR}/${ORTHANC_FILENAME} - -mkdir -p ${TARGET}/Resources/ThirdParty -mkdir -p ${TARGET}/Plugins/Samples/Common - -cp ${SOURCE}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp ${TARGET}/Plugins/Samples/Common -cp ${SOURCE}/Plugins/Samples/Common/OrthancPluginCppWrapper.h ${TARGET}/Plugins/Samples/Common -cp ${SOURCE}/Plugins/Samples/Common/OrthancPluginException.h ${TARGET}/Plugins/Samples/Common -cp ${SOURCE}/Plugins/Samples/Common/VersionScript.map ${TARGET}/Plugins/Samples/Common - -cp -r ${SOURCE}/AUTHORS ${TARGET} -cp -r ${SOURCE}/COPYING ${TARGET} -cp -r ${SOURCE}/Core ${TARGET} -cp -r ${SOURCE}/NEWS ${TARGET} -cp -r ${SOURCE}/OrthancServer ${TARGET} -cp -r ${SOURCE}/README ${TARGET} -cp -r ${SOURCE}/Resources/CMake ${TARGET}/Resources -cp -r ${SOURCE}/Resources/EmbedResources.py ${TARGET}/Resources -cp -r ${SOURCE}/Resources/ThirdParty/base64 ${TARGET}/Resources/ThirdParty -cp -r ${SOURCE}/Resources/ThirdParty/md5 ${TARGET}/Resources/ThirdParty -cp -r ${SOURCE}/Resources/ThirdParty/minizip ${TARGET}/Resources/ThirdParty diff -Nru orthanc-mysql-2.0/debian/orthanc-framework/README orthanc-mysql-3.0/debian/orthanc-framework/README --- orthanc-mysql-2.0/debian/orthanc-framework/README 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/orthanc-framework/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,7 +0,0 @@ -This file contains a copy of the Orthanc framework. - -This framework consists of source code that is shared by all the -official plugins from the Orthanc project. - -In the future, the Orthanc framework might be packaged as a real -shared library, but this requires complex upstream work. diff -Nru orthanc-mysql-2.0/debian/patches/mysql8_my_bool.patch orthanc-mysql-3.0/debian/patches/mysql8_my_bool.patch --- orthanc-mysql-2.0/debian/patches/mysql8_my_bool.patch 2020-02-21 16:55:01.000000000 +0000 +++ orthanc-mysql-3.0/debian/patches/mysql8_my_bool.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -Description: Reintroduce my_bool to fix build with MySQL 8 -Author: Andreas Hasenack -Bug-Ubuntu: https://bugs.launchpad.net/bugs/1863026 -Forwarded: no -Last-Update: 2020-02-12 ---- -This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ -diff --git a/Framework/MySQL/MySQLDatabase.h b/Framework/MySQL/MySQLDatabase.h -index 32fc474..e4f5b00 100644 ---- a/Framework/MySQL/MySQLDatabase.h -+++ b/Framework/MySQL/MySQLDatabase.h -@@ -29,6 +29,7 @@ - #include "MySQLParameters.h" - - #include -+typedef bool my_bool; - - namespace OrthancDatabases - { diff -Nru orthanc-mysql-2.0/debian/patches/series orthanc-mysql-3.0/debian/patches/series --- orthanc-mysql-2.0/debian/patches/series 2020-07-31 12:48:09.000000000 +0000 +++ orthanc-mysql-3.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -mysql8_my_bool.patch diff -Nru orthanc-mysql-2.0/debian/rules orthanc-mysql-3.0/debian/rules --- orthanc-mysql-2.0/debian/rules 2020-06-05 08:33:02.000000000 +0000 +++ orthanc-mysql-3.0/debian/rules 2020-12-17 07:58:15.000000000 +0000 @@ -20,8 +20,7 @@ -DCMAKE_SKIP_RPATH:BOOL=ON \ -DSTATIC_BUILD:BOOL=OFF \ -DUSE_GOOGLE_TEST_DEBIAN_PACKAGE:BOOL=ON \ - -DORTHANC_FRAMEWORK_SOURCE=path \ - -DORTHANC_FRAMEWORK_ROOT=`pwd`/debian/orthanc-framework/Orthanc-1.7.0 \ + -DORTHANC_FRAMEWORK_SOURCE=system \ -DDEB_VERSION=$(DEB_VERSION) \ -DCMAKE_BUILD_TYPE=None # The build type must be set to None, see #711515 diff -Nru orthanc-mysql-2.0/Framework/Common/BinaryStringValue.cpp orthanc-mysql-3.0/Framework/Common/BinaryStringValue.cpp --- orthanc-mysql-2.0/Framework/Common/BinaryStringValue.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/BinaryStringValue.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -24,7 +24,7 @@ #include "FileValue.h" #include "NullValue.h" -#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/BinaryStringValue.h orthanc-mysql-3.0/Framework/Common/BinaryStringValue.h --- orthanc-mysql-2.0/Framework/Common/BinaryStringValue.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/BinaryStringValue.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "IValue.h" +#include + namespace OrthancDatabases { class BinaryStringValue : public IValue @@ -66,13 +68,13 @@ return content_.size(); } - virtual ValueType GetType() const + virtual ValueType GetType() const ORTHANC_OVERRIDE { return ValueType_BinaryString; } - virtual IValue* Convert(ValueType target) const; + virtual IValue* Convert(ValueType target) const ORTHANC_OVERRIDE; - virtual std::string Format() const; + virtual std::string Format() const ORTHANC_OVERRIDE; }; } diff -Nru orthanc-mysql-2.0/Framework/Common/DatabaseManager.cpp orthanc-mysql-3.0/Framework/Common/DatabaseManager.cpp --- orthanc-mysql-2.0/Framework/Common/DatabaseManager.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/DatabaseManager.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,8 +21,11 @@ #include "DatabaseManager.h" -#include -#include +#include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" + +#include // For std::unique_ptr<> +#include +#include #include @@ -30,9 +33,11 @@ { IDatabase& DatabaseManager::GetDatabase() { - static const unsigned int MAX_CONNECTION_ATTEMPTS = 10; // TODO: Parameter - + unsigned int maxConnectionRetries = 10; + unsigned int connectionRetryInterval = 5; unsigned int count = 0; + + factory_->GetConnectionRetriesParameters(maxConnectionRetries, connectionRetryInterval); while (database_.get() == NULL) { @@ -48,10 +53,10 @@ { count ++; - if (count <= MAX_CONNECTION_ATTEMPTS) + if (count <= maxConnectionRetries) { LOG(WARNING) << "Database is currently unavailable, retrying..."; - boost::this_thread::sleep(boost::posix_time::seconds(1)); + boost::this_thread::sleep(boost::posix_time::seconds(connectionRetryInterval)); continue; } else @@ -137,7 +142,7 @@ { LOG(TRACE) << "Caching statement from " << location.GetFile() << ":" << location.GetLine(); - std::auto_ptr statement(GetDatabase().Compile(query)); + std::unique_ptr statement(GetDatabase().Compile(query)); IPrecompiledStatement* tmp = statement.get(); if (tmp == NULL) @@ -334,7 +339,7 @@ void DatabaseManager::StatementBase::SetQuery(Query* query) { - std::auto_ptr protection(query); + std::unique_ptr protection(query); if (query_.get() != NULL) { @@ -353,7 +358,7 @@ void DatabaseManager::StatementBase::SetResult(IResult* result) { - std::auto_ptr protection(result); + std::unique_ptr protection(result); if (result_.get() != NULL) { @@ -500,7 +505,7 @@ { try { - std::auto_ptr query(ReleaseQuery()); + std::unique_ptr query(ReleaseQuery()); if (query.get() != NULL) { @@ -510,6 +515,18 @@ } assert(statement_ != NULL); + + /* + TODO - Sample code to monitor the execution time of each + cached statement, and publish it as an Orthanc metrics + + #if HAS_ORTHANC_PLUGIN_METRICS == 1 + std::string name = (std::string(location_.GetFile()) + "_" + + boost::lexical_cast(location_.GetLine())); + OrthancPlugins::MetricsTimer timer(name.c_str()); + #endif + */ + SetResult(GetTransaction().Execute(*statement_, parameters)); } catch (Orthanc::OrthancException& e) @@ -540,7 +557,7 @@ { try { - std::auto_ptr query(ReleaseQuery()); + std::unique_ptr query(ReleaseQuery()); assert(query.get() != NULL); // The "statement_" object must be kept as long as the "IResult" diff -Nru orthanc-mysql-2.0/Framework/Common/DatabaseManager.h orthanc-mysql-3.0/Framework/Common/DatabaseManager.h --- orthanc-mysql-2.0/Framework/Common/DatabaseManager.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/DatabaseManager.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -24,7 +24,8 @@ #include "IDatabaseFactory.h" #include "StatementLocation.h" -#include +#include // For std::unique_ptr<> +#include #include #include @@ -37,9 +38,9 @@ typedef std::map CachedStatements; boost::recursive_mutex mutex_; - std::auto_ptr factory_; - std::auto_ptr database_; - std::auto_ptr transaction_; + std::unique_ptr factory_; + std::unique_ptr database_; + std::unique_ptr transaction_; CachedStatements cachedStatements_; Dialect dialect_; @@ -117,8 +118,8 @@ DatabaseManager& manager_; boost::recursive_mutex::scoped_lock lock_; ITransaction& transaction_; - std::auto_ptr query_; - std::auto_ptr result_; + std::unique_ptr query_; + std::unique_ptr result_; IResult& GetResult() const; @@ -200,7 +201,7 @@ class StandaloneStatement : public StatementBase { private: - std::auto_ptr statement_; + std::unique_ptr statement_; public: StandaloneStatement(DatabaseManager& manager, diff -Nru orthanc-mysql-2.0/Framework/Common/DatabasesEnumerations.h orthanc-mysql-3.0/Framework/Common/DatabasesEnumerations.h --- orthanc-mysql-2.0/Framework/Common/DatabasesEnumerations.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/DatabasesEnumerations.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/Dictionary.cpp orthanc-mysql-3.0/Framework/Common/Dictionary.cpp --- orthanc-mysql-2.0/Framework/Common/Dictionary.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Dictionary.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -27,8 +27,8 @@ #include "NullValue.h" #include "Utf8StringValue.h" -#include -#include +#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/Dictionary.h orthanc-mysql-3.0/Framework/Common/Dictionary.h --- orthanc-mysql-2.0/Framework/Common/Dictionary.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Dictionary.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/FileValue.cpp orthanc-mysql-3.0/Framework/Common/FileValue.cpp --- orthanc-mysql-2.0/Framework/Common/FileValue.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/FileValue.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -24,7 +24,7 @@ #include "BinaryStringValue.h" #include "NullValue.h" -#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/FileValue.h orthanc-mysql-3.0/Framework/Common/FileValue.h --- orthanc-mysql-2.0/Framework/Common/FileValue.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/FileValue.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "IValue.h" +#include + namespace OrthancDatabases { class FileValue : public IValue @@ -76,13 +78,13 @@ return content_.size(); } - virtual ValueType GetType() const + virtual ValueType GetType() const ORTHANC_OVERRIDE { return ValueType_File; } - virtual IValue* Convert(ValueType target) const; + virtual IValue* Convert(ValueType target) const ORTHANC_OVERRIDE; - virtual std::string Format() const; + virtual std::string Format() const ORTHANC_OVERRIDE; }; } diff -Nru orthanc-mysql-2.0/Framework/Common/GenericFormatter.cpp orthanc-mysql-3.0/Framework/Common/GenericFormatter.cpp --- orthanc-mysql-2.0/Framework/Common/GenericFormatter.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/GenericFormatter.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,7 +21,7 @@ #include "GenericFormatter.h" -#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/GenericFormatter.h orthanc-mysql-3.0/Framework/Common/GenericFormatter.h --- orthanc-mysql-2.0/Framework/Common/GenericFormatter.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/GenericFormatter.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "Query.h" +#include + namespace OrthancDatabases { class GenericFormatter : public Query::IParameterFormatter @@ -38,9 +40,9 @@ { } - void Format(std::string& target, - const std::string& source, - ValueType type); + virtual void Format(std::string& target, + const std::string& source, + ValueType type) ORTHANC_OVERRIDE; size_t GetParametersCount() const { diff -Nru orthanc-mysql-2.0/Framework/Common/IDatabaseFactory.h orthanc-mysql-3.0/Framework/Common/IDatabaseFactory.h --- orthanc-mysql-2.0/Framework/Common/IDatabaseFactory.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/IDatabaseFactory.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -35,5 +35,7 @@ virtual Dialect GetDialect() const = 0; virtual IDatabase* Open() = 0; + + virtual void GetConnectionRetriesParameters(unsigned int& maxConnectionRetries, unsigned int& connectionRetryInterval) = 0; }; } diff -Nru orthanc-mysql-2.0/Framework/Common/IDatabase.h orthanc-mysql-3.0/Framework/Common/IDatabase.h --- orthanc-mysql-2.0/Framework/Common/IDatabase.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/IDatabase.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/ImplicitTransaction.cpp orthanc-mysql-3.0/Framework/Common/ImplicitTransaction.cpp --- orthanc-mysql-2.0/Framework/Common/ImplicitTransaction.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/ImplicitTransaction.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,8 +21,9 @@ #include "ImplicitTransaction.h" -#include -#include +#include // For std::unique_ptr<> +#include +#include #include @@ -124,7 +125,7 @@ const Dictionary& parameters) { CheckStateForExecution(); - std::auto_ptr result(ExecuteInternal(statement, parameters)); + std::unique_ptr result(ExecuteInternal(statement, parameters)); if (!statement.IsReadOnly()) { diff -Nru orthanc-mysql-2.0/Framework/Common/ImplicitTransaction.h orthanc-mysql-3.0/Framework/Common/ImplicitTransaction.h --- orthanc-mysql-2.0/Framework/Common/ImplicitTransaction.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/ImplicitTransaction.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "ITransaction.h" +#include + namespace OrthancDatabases { class ImplicitTransaction : public ITransaction @@ -52,25 +54,25 @@ virtual ~ImplicitTransaction(); - virtual bool IsImplicit() const + virtual bool IsImplicit() const ORTHANC_OVERRIDE { return true; } - virtual bool IsReadOnly() const + virtual bool IsReadOnly() const ORTHANC_OVERRIDE { return readOnly_; } - virtual void Rollback(); + virtual void Rollback() ORTHANC_OVERRIDE; - virtual void Commit(); + virtual void Commit() ORTHANC_OVERRIDE; virtual IResult* Execute(IPrecompiledStatement& statement, - const Dictionary& parameters); + const Dictionary& parameters) ORTHANC_OVERRIDE; virtual void ExecuteWithoutResult(IPrecompiledStatement& statement, - const Dictionary& parameters); + const Dictionary& parameters) ORTHANC_OVERRIDE; static void SetErrorOnDoubleExecution(bool isError); diff -Nru orthanc-mysql-2.0/Framework/Common/Integer64Value.cpp orthanc-mysql-3.0/Framework/Common/Integer64Value.cpp --- orthanc-mysql-2.0/Framework/Common/Integer64Value.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Integer64Value.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -26,7 +26,7 @@ #include "NullValue.h" #include "Utf8StringValue.h" -#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/Integer64Value.h orthanc-mysql-3.0/Framework/Common/Integer64Value.h --- orthanc-mysql-2.0/Framework/Common/Integer64Value.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Integer64Value.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "IValue.h" +#include + #include namespace OrthancDatabases @@ -43,13 +45,13 @@ return value_; } - virtual ValueType GetType() const + virtual ValueType GetType() const ORTHANC_OVERRIDE { return ValueType_Integer64; } - virtual IValue* Convert(ValueType target) const; + virtual IValue* Convert(ValueType target) const ORTHANC_OVERRIDE; - virtual std::string Format() const; + virtual std::string Format() const ORTHANC_OVERRIDE; }; } diff -Nru orthanc-mysql-2.0/Framework/Common/IPrecompiledStatement.h orthanc-mysql-3.0/Framework/Common/IPrecompiledStatement.h --- orthanc-mysql-2.0/Framework/Common/IPrecompiledStatement.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/IPrecompiledStatement.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/IResult.h orthanc-mysql-3.0/Framework/Common/IResult.h --- orthanc-mysql-2.0/Framework/Common/IResult.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/IResult.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/ITransaction.h orthanc-mysql-3.0/Framework/Common/ITransaction.h --- orthanc-mysql-2.0/Framework/Common/ITransaction.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/ITransaction.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/IValue.h orthanc-mysql-3.0/Framework/Common/IValue.h --- orthanc-mysql-2.0/Framework/Common/IValue.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/IValue.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/NullValue.cpp orthanc-mysql-3.0/Framework/Common/NullValue.cpp --- orthanc-mysql-2.0/Framework/Common/NullValue.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/NullValue.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,7 +21,7 @@ #include "NullValue.h" -#include +#include namespace OrthancDatabases { diff -Nru orthanc-mysql-2.0/Framework/Common/NullValue.h orthanc-mysql-3.0/Framework/Common/NullValue.h --- orthanc-mysql-2.0/Framework/Common/NullValue.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/NullValue.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,19 +23,21 @@ #include "IValue.h" +#include + namespace OrthancDatabases { class NullValue : public IValue { public: - virtual ValueType GetType() const + virtual ValueType GetType() const ORTHANC_OVERRIDE { return ValueType_Null; } - virtual IValue* Convert(ValueType target) const; + virtual IValue* Convert(ValueType target) const ORTHANC_OVERRIDE; - virtual std::string Format() const + virtual std::string Format() const ORTHANC_OVERRIDE { return "(null)"; } diff -Nru orthanc-mysql-2.0/Framework/Common/Query.cpp orthanc-mysql-3.0/Framework/Common/Query.cpp --- orthanc-mysql-2.0/Framework/Common/Query.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Query.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,8 +21,8 @@ #include "Query.h" -#include -#include +#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/Query.h orthanc-mysql-3.0/Framework/Common/Query.h --- orthanc-mysql-2.0/Framework/Common/Query.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Query.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/ResultBase.cpp orthanc-mysql-3.0/Framework/Common/ResultBase.cpp --- orthanc-mysql-2.0/Framework/Common/ResultBase.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/ResultBase.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -26,8 +26,9 @@ #include "../Common/NullValue.h" #include "../Common/Utf8StringValue.h" -#include -#include +#include // For std::unique_ptr<> +#include +#include #include #include @@ -66,7 +67,7 @@ sourceType != ValueType_Null && sourceType != targetType) { - std::auto_ptr converted(fields_[i]->Convert(targetType)); + std::unique_ptr converted(fields_[i]->Convert(targetType)); if (converted.get() == NULL) { diff -Nru orthanc-mysql-2.0/Framework/Common/ResultBase.h orthanc-mysql-3.0/Framework/Common/ResultBase.h --- orthanc-mysql-2.0/Framework/Common/ResultBase.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/ResultBase.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "IResult.h" +#include + #include namespace OrthancDatabases @@ -52,13 +54,13 @@ } virtual void SetExpectedType(size_t field, - ValueType type); + ValueType type) ORTHANC_OVERRIDE; - virtual size_t GetFieldsCount() const + virtual size_t GetFieldsCount() const ORTHANC_OVERRIDE { return fields_.size(); } - virtual const IValue& GetField(size_t index) const; + virtual const IValue& GetField(size_t index) const ORTHANC_OVERRIDE; }; } diff -Nru orthanc-mysql-2.0/Framework/Common/StatementLocation.cpp orthanc-mysql-3.0/Framework/Common/StatementLocation.cpp --- orthanc-mysql-2.0/Framework/Common/StatementLocation.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/StatementLocation.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/StatementLocation.h orthanc-mysql-3.0/Framework/Common/StatementLocation.h --- orthanc-mysql-2.0/Framework/Common/StatementLocation.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/StatementLocation.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Common/Utf8StringValue.cpp orthanc-mysql-3.0/Framework/Common/Utf8StringValue.cpp --- orthanc-mysql-2.0/Framework/Common/Utf8StringValue.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Utf8StringValue.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -26,7 +26,7 @@ #include "NullValue.h" #include "Integer64Value.h" -#include +#include #include diff -Nru orthanc-mysql-2.0/Framework/Common/Utf8StringValue.h orthanc-mysql-3.0/Framework/Common/Utf8StringValue.h --- orthanc-mysql-2.0/Framework/Common/Utf8StringValue.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Common/Utf8StringValue.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,6 +23,8 @@ #include "IValue.h" +#include + namespace OrthancDatabases { // Represents an UTF-8 string @@ -51,14 +53,14 @@ return utf8_; } - virtual ValueType GetType() const + virtual ValueType GetType() const ORTHANC_OVERRIDE { return ValueType_Utf8String; } - virtual IValue* Convert(ValueType target) const; + virtual IValue* Convert(ValueType target) const ORTHANC_OVERRIDE; - virtual std::string Format() const + virtual std::string Format() const ORTHANC_OVERRIDE { return "[" + utf8_ + "]"; } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLDatabase.cpp orthanc-mysql-3.0/Framework/MySQL/MySQLDatabase.cpp --- orthanc-mysql-2.0/Framework/MySQL/MySQLDatabase.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLDatabase.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -27,14 +27,16 @@ #include "../Common/ImplicitTransaction.h" #include "../Common/Integer64Value.h" -#include -#include -#include +#include // For std::unique_ptr<> +#include +#include +#include #include #include #include +#include namespace OrthancDatabases { @@ -138,7 +140,25 @@ unsigned int protocol = MYSQL_PROTOCOL_TCP; mysql_options(mysql_, MYSQL_OPT_PROTOCOL, (unsigned int *) &protocol); } - + + if (parameters_.IsSsl()) + { + if (parameters_.IsVerifyServerCertificates()) + { +#if (MYSQL_VERSION_ID > 50110 && MYSQL_VERSION_ID < 80000) // Removed in MySQL client 8.0 + my_bool verifyCert = 1; + mysql_options(mysql_, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (void *) &verifyCert); +#endif + + mysql_options(mysql_, MYSQL_OPT_SSL_CA, (void *)(parameters_.GetSslCaCertificates())); + } + +#if (MYSQL_VERSION_ID > 50110 && MYSQL_VERSION_ID < 80000) // Removed in MySQL client 8.0 + my_bool enforceTls = 1; + mysql_options(mysql_, MYSQL_OPT_SSL_ENFORCE, (void *) &enforceTls); +#endif + } + const char* socket = (parameters_.GetUnixSocket().empty() ? NULL : parameters_.GetUnixSocket().c_str()); @@ -289,32 +309,69 @@ } - void MySQLDatabase::AdvisoryLock(int32_t lock) + bool MySQLDatabase::RunAdvisoryLockStatement(Query& query, + const std::string& lock) { - try + const std::string& dbName = parameters_.GetDatabase(); + + // Prepend the name of the lock by the database name. This allows + // to create a namespace for advisory locks: + // https://groups.google.com/d/msg/orthanc-users/yV3LSTh_TjI/MQIcvnMlAQAJ + std::string prefix; + prefix.reserve(dbName.size()); + for (size_t i = 0; i < dbName.size(); i++) { - Query query("SELECT GET_LOCK('Lock" + - boost::lexical_cast(lock) + "', 0);", false); - MySQLStatement statement(*this, query); + if (isalnum(dbName[i]) || + dbName[i] == '$' || + dbName[i] == '_') + { + prefix.push_back(dbName[i]); + } + } - MySQLTransaction t(*this); - Dictionary args; + query.SetType("lock", ValueType_Utf8String); + + Dictionary args; + args.SetUtf8Value("lock", prefix + "." + lock); - std::auto_ptr result(t.Execute(statement, args)); + bool success; - if (result->IsDone() || - result->GetField(0).GetType() != ValueType_Integer64 || - dynamic_cast(result->GetField(0)).GetValue() != 1) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); - } + { + MySQLStatement statement(*this, query); + MySQLTransaction t(*this); + std::unique_ptr result(t.Execute(statement, args)); + + success = (!result->IsDone() && + result->GetField(0).GetType() == ValueType_Integer64 && + dynamic_cast(result->GetField(0)).GetValue() == 1); + t.Commit(); } - catch (Orthanc::OrthancException&) + + return success; + } + + + bool MySQLDatabase::AcquireAdvisoryLock(const std::string& lock) + { + Query query("SELECT GET_LOCK(${lock}, 0)", false); + return RunAdvisoryLockStatement(query, lock); + } + + + bool MySQLDatabase::ReleaseAdvisoryLock(const std::string& lock) + { + Query query("SELECT RELEASE_LOCK(${lock})", false); + return RunAdvisoryLockStatement(query, lock); + } + + + void MySQLDatabase::AdvisoryLock(const std::string& lock) + { + if (!AcquireAdvisoryLock(lock)) { LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc"; - Close(); throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); } } @@ -344,7 +401,7 @@ args.SetUtf8Value("database", parameters_.GetDatabase()); args.SetUtf8Value("table", name); - std::auto_ptr result(statement.Execute(transaction, args)); + std::unique_ptr result(statement.Execute(transaction, args)); return (!result->IsDone() && result->GetFieldsCount() == 1 && result->GetField(0).GetType() == ValueType_Integer64 && @@ -374,7 +431,7 @@ Dictionary args; args.SetUtf8Value("database", name); - std::auto_ptr result(statement.Execute(transaction, args)); + std::unique_ptr result(statement.Execute(transaction, args)); return (!result->IsDone() && result->GetFieldsCount() == 1 && result->GetField(0).GetType() == ValueType_Integer64 && @@ -382,6 +439,36 @@ } + bool MySQLDatabase::DoesTriggerExist(MySQLTransaction& transaction, + const std::string& name) + { + if (mysql_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + if (!IsValidDatabaseIdentifier(name)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + Query query("SELECT COUNT(*) FROM information_schema.TRIGGERS " + "WHERE TRIGGER_NAME = ${trigger}", true); + query.SetType("trigger", ValueType_Utf8String); + + MySQLStatement statement(*this, query); + + Dictionary args; + args.SetUtf8Value("trigger", name); + + std::unique_ptr result(statement.Execute(transaction, args)); + return (!result->IsDone() && + result->GetFieldsCount() == 1 && + result->GetField(0).GetType() == ValueType_Integer64 && + dynamic_cast(result->GetField(0)).GetValue() != 0); + } + + void MySQLDatabase::Execute(const std::string& sql, bool arobaseSeparator) { @@ -448,7 +535,7 @@ } public: - MySQLImplicitTransaction(MySQLDatabase& db) : + explicit MySQLImplicitTransaction(MySQLDatabase& db) : db_(db) { } @@ -495,4 +582,39 @@ return true; } + + + MySQLDatabase::TransientAdvisoryLock:: + TransientAdvisoryLock(MySQLDatabase& database, + const std::string& lock) : + database_(database), + lock_(lock) + { + bool locked = true; + + for (unsigned int i = 0; i < 10; i++) + { + if (database_.AcquireAdvisoryLock(lock_)) + { + locked = false; + break; + } + else + { + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + } + } + + if (locked) + { + LOG(ERROR) << "Cannot acquire a transient advisory lock"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin); + } + } + + + MySQLDatabase::TransientAdvisoryLock::~TransientAdvisoryLock() + { + database_.ReleaseAdvisoryLock(lock_); + } } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLDatabase.h orthanc-mysql-3.0/Framework/MySQL/MySQLDatabase.h --- orthanc-mysql-2.0/Framework/MySQL/MySQLDatabase.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLDatabase.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -44,8 +44,11 @@ void Close(); + bool RunAdvisoryLockStatement(Query& query, + const std::string& lock); + public: - MySQLDatabase(const MySQLParameters& parameters); + explicit MySQLDatabase(const MySQLParameters& parameters); virtual ~MySQLDatabase(); @@ -70,7 +73,11 @@ bool LookupGlobalIntegerVariable(int64_t& value, const std::string& variable); - void AdvisoryLock(int32_t lock); + bool AcquireAdvisoryLock(const std::string& lock); + + bool ReleaseAdvisoryLock(const std::string& lock); + + void AdvisoryLock(const std::string& lock); void Execute(const std::string& sql, bool arobaseSeparator); @@ -81,17 +88,33 @@ bool DoesDatabaseExist(MySQLTransaction& transaction, const std::string& name); - virtual Dialect GetDialect() const + bool DoesTriggerExist(MySQLTransaction& transaction, + const std::string& name); + + virtual Dialect GetDialect() const ORTHANC_OVERRIDE { return Dialect_MySQL; } - virtual IPrecompiledStatement* Compile(const Query& query); + virtual IPrecompiledStatement* Compile(const Query& query) ORTHANC_OVERRIDE; - virtual ITransaction* CreateTransaction(bool isImplicit); + virtual ITransaction* CreateTransaction(bool isImplicit) ORTHANC_OVERRIDE; static void GlobalFinalization(); static bool IsValidDatabaseIdentifier(const std::string& s); + + class TransientAdvisoryLock + { + private: + MySQLDatabase& database_; + std::string lock_; + + public: + TransientAdvisoryLock(MySQLDatabase& database, + const std::string& lock); + + ~TransientAdvisoryLock(); + }; }; } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLParameters.cpp orthanc-mysql-3.0/Framework/MySQL/MySQLParameters.cpp --- orthanc-mysql-2.0/Framework/MySQL/MySQLParameters.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLParameters.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,8 +23,8 @@ #include "MySQLDatabase.h" -#include -#include +#include +#include namespace OrthancDatabases { @@ -46,49 +46,69 @@ } - MySQLParameters::MySQLParameters() + MySQLParameters::MySQLParameters() : + ssl_(false), + verifySslServerCertificates_(true), + maxConnectionRetries_(10), + connectionRetryInterval_(5) { Reset(); } - MySQLParameters::MySQLParameters(const OrthancPlugins::OrthancConfiguration& configuration) + MySQLParameters::MySQLParameters(const OrthancPlugins::OrthancConfiguration& pluginConfiguration, + const OrthancPlugins::OrthancConfiguration& orthancConfiguration) { Reset(); std::string s; - if (configuration.LookupStringValue(s, "Host")) + if (pluginConfiguration.LookupStringValue(s, "Host")) { SetHost(s); } - if (configuration.LookupStringValue(s, "Username")) + if (pluginConfiguration.LookupStringValue(s, "Username")) { SetUsername(s); } - if (configuration.LookupStringValue(s, "Password")) + if (pluginConfiguration.LookupStringValue(s, "Password")) { SetPassword(s); } - if (configuration.LookupStringValue(s, "Database")) + if (pluginConfiguration.LookupStringValue(s, "Database")) { SetDatabase(s); } unsigned int port; - if (configuration.LookupUnsignedIntegerValue(port, "Port")) + if (pluginConfiguration.LookupUnsignedIntegerValue(port, "Port")) { SetPort(port); } - if (configuration.LookupStringValue(s, "UnixSocket")) + if (pluginConfiguration.LookupStringValue(s, "UnixSocket")) { SetUnixSocket(s); } - lock_ = configuration.GetBooleanValue("Lock", true); // Use locking by default + lock_ = pluginConfiguration.GetBooleanValue("Lock", true); // Use locking by default + + ssl_ = pluginConfiguration.GetBooleanValue("EnableSsl", false); + verifySslServerCertificates_ = pluginConfiguration.GetBooleanValue("SslVerifyServerCertificates", true); + + const std::string defaultCaCertificates = orthancConfiguration.GetStringValue("HttpsCACertificates", ""); + sslCaCertificates_ = pluginConfiguration.GetStringValue("SslCACertificates", defaultCaCertificates); + + if (ssl_ && verifySslServerCertificates_ && sslCaCertificates_.empty()) + { + LOG(ERROR) << "MySQL: No SslCACertificates defined, unable to check SSL Server certificates"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + maxConnectionRetries_ = pluginConfiguration.GetUnsignedIntegerValue("MaximumConnectionRetries", 10); + connectionRetryInterval_ = pluginConfiguration.GetUnsignedIntegerValue("ConnectionRetryInterval", 5); } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLParameters.h orthanc-mysql-3.0/Framework/MySQL/MySQLParameters.h --- orthanc-mysql-2.0/Framework/MySQL/MySQLParameters.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLParameters.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -25,7 +25,7 @@ # error MySQL support must be enabled to use this file #endif -#include +#include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" namespace OrthancDatabases { @@ -38,14 +38,20 @@ std::string database_; uint16_t port_; std::string unixSocket_; + bool ssl_; + bool verifySslServerCertificates_; + std::string sslCaCertificates_; bool lock_; + unsigned int maxConnectionRetries_; + unsigned int connectionRetryInterval_; void Reset(); - + public: MySQLParameters(); - MySQLParameters(const OrthancPlugins::OrthancConfiguration& configuration); + MySQLParameters(const OrthancPlugins::OrthancConfiguration& pluginConfiguration, + const OrthancPlugins::OrthancConfiguration& orthancConfiguration); const std::string& GetHost() const { @@ -77,6 +83,21 @@ return port_; } + bool IsSsl() const + { + return ssl_; + } + + bool IsVerifyServerCertificates() const + { + return verifySslServerCertificates_; + } + + const char* GetSslCaCertificates() const + { + return sslCaCertificates_.c_str(); + } + void SetHost(const std::string& host); void SetUsername(const std::string& username); @@ -99,6 +120,16 @@ return lock_; } + unsigned int GetMaxConnectionRetries() const + { + return maxConnectionRetries_; + } + + unsigned int GetConnectionRetryInterval() const + { + return connectionRetryInterval_; + } + void Format(Json::Value& target) const; }; } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLResult.cpp orthanc-mysql-3.0/Framework/MySQL/MySQLResult.cpp --- orthanc-mysql-2.0/Framework/MySQL/MySQLResult.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLResult.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,8 +21,8 @@ #include "MySQLResult.h" -#include -#include +#include +#include #include #include diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLResult.h orthanc-mysql-3.0/Framework/MySQL/MySQLResult.h --- orthanc-mysql-2.0/Framework/MySQL/MySQLResult.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLResult.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -40,19 +40,19 @@ void Step(); protected: - virtual IValue* FetchField(size_t index); + virtual IValue* FetchField(size_t index) ORTHANC_OVERRIDE; public: MySQLResult(MySQLDatabase& db, MySQLStatement& statement); - virtual ~MySQLResult(); + virtual ~MySQLResult() ORTHANC_OVERRIDE; - virtual bool IsDone() const + virtual bool IsDone() const ORTHANC_OVERRIDE { return done_; } - virtual void Next(); + virtual void Next() ORTHANC_OVERRIDE; }; } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLStatement.cpp orthanc-mysql-3.0/Framework/MySQL/MySQLStatement.cpp --- orthanc-mysql-2.0/Framework/MySQL/MySQLStatement.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLStatement.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -28,8 +28,9 @@ #include "../Common/Utf8StringValue.h" #include "MySQLResult.h" -#include -#include +#include // For std::unique_ptr<> +#include +#include #include #include @@ -39,7 +40,7 @@ class MySQLStatement::ResultField : public boost::noncopyable { private: - IValue* CreateIntegerValue(MYSQL_BIND& bind) const + IValue* CreateIntegerValue(const MYSQL_BIND& bind) const { if (length_ != buffer_.size()) { @@ -109,14 +110,21 @@ enum enum_field_types mysqlType_; ValueType orthancType_; std::string buffer_; + +#if (MYSQL_VERSION_ID < 80000) || defined(MARIADB_VERSION_ID) my_bool isNull_; my_bool isError_; +#else + bool isNull_; + bool isError_; +#endif + unsigned long length_; - public: - ResultField(const MYSQL_FIELD& field) : - mysqlType_(field.type) + explicit ResultField(const MYSQL_FIELD& field) : + mysqlType_(field.type), + length_(0) { // https://dev.mysql.com/doc/refman/8.0/en/c-api-data-structures.html // https://dev.mysql.com/doc/refman/8.0/en/mysql-stmt-fetch.html => size of "buffer_" @@ -354,7 +362,7 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); } - LOG(INFO) << "Preparing MySQL statement: " << sql; + LOG(TRACE) << "Preparing MySQL statement: " << sql; db_.CheckErrorCode(mysql_stmt_prepare(statement_, sql.c_str(), sql.size())); @@ -439,7 +447,6 @@ IResult* MySQLStatement::Execute(ITransaction& transaction, const Dictionary& parameters) { - std::list intParameters; std::list int64Parameters; std::vector inputs(formatter_.GetParametersCount()); @@ -542,6 +549,6 @@ void MySQLStatement::ExecuteWithoutResult(ITransaction& transaction, const Dictionary& parameters) { - std::auto_ptr dummy(Execute(transaction, parameters)); + std::unique_ptr dummy(Execute(transaction, parameters)); } } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLStatement.h orthanc-mysql-3.0/Framework/MySQL/MySQLStatement.h --- orthanc-mysql-2.0/Framework/MySQL/MySQLStatement.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLStatement.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -51,7 +51,7 @@ virtual ~MySQLStatement(); - virtual bool IsReadOnly() const + virtual bool IsReadOnly() const ORTHANC_OVERRIDE { return readOnly_; } diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLTransaction.cpp orthanc-mysql-3.0/Framework/MySQL/MySQLTransaction.cpp --- orthanc-mysql-2.0/Framework/MySQL/MySQLTransaction.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLTransaction.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,8 +23,9 @@ #include "MySQLStatement.h" -#include -#include +#include // For std::unique_ptr<> +#include +#include #include @@ -93,7 +94,7 @@ IResult* MySQLTransaction::Execute(IPrecompiledStatement& statement, const Dictionary& parameters) { - std::auto_ptr result(dynamic_cast(statement).Execute(*this, parameters)); + std::unique_ptr result(dynamic_cast(statement).Execute(*this, parameters)); if (!statement.IsReadOnly()) { diff -Nru orthanc-mysql-2.0/Framework/MySQL/MySQLTransaction.h orthanc-mysql-3.0/Framework/MySQL/MySQLTransaction.h --- orthanc-mysql-2.0/Framework/MySQL/MySQLTransaction.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/MySQL/MySQLTransaction.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -38,28 +38,28 @@ bool active_; public: - MySQLTransaction(MySQLDatabase& db); + explicit MySQLTransaction(MySQLDatabase& db); virtual ~MySQLTransaction(); - virtual bool IsImplicit() const + virtual bool IsImplicit() const ORTHANC_OVERRIDE { return false; } - virtual bool IsReadOnly() const + virtual bool IsReadOnly() const ORTHANC_OVERRIDE { return readOnly_; } - virtual void Rollback(); + virtual void Rollback() ORTHANC_OVERRIDE; - virtual void Commit(); + virtual void Commit() ORTHANC_OVERRIDE; virtual IResult* Execute(IPrecompiledStatement& statement, - const Dictionary& parameters); + const Dictionary& parameters) ORTHANC_OVERRIDE; virtual void ExecuteWithoutResult(IPrecompiledStatement& transaction, - const Dictionary& parameters); + const Dictionary& parameters) ORTHANC_OVERRIDE; }; } diff -Nru orthanc-mysql-2.0/Framework/Plugins/GlobalProperties.cpp orthanc-mysql-3.0/Framework/Plugins/GlobalProperties.cpp --- orthanc-mysql-2.0/Framework/Plugins/GlobalProperties.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/GlobalProperties.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,8 +23,9 @@ #include "../Common/Utf8StringValue.h" -#include -#include +#include // For std::unique_ptr<> +#include +#include #include @@ -38,12 +39,12 @@ Query query("SELECT value FROM GlobalProperties WHERE property=${property}", true); query.SetType("property", ValueType_Integer64); - std::auto_ptr statement(db.Compile(query)); + std::unique_ptr statement(db.Compile(query)); Dictionary args; args.SetIntegerValue("property", property); - std::auto_ptr result(transaction.Execute(*statement, args)); + std::unique_ptr result(transaction.Execute(*statement, args)); if (result->IsDone()) { @@ -115,13 +116,19 @@ Orthanc::GlobalProperty property, const std::string& utf8) { + // This version of "SetGlobalProperty()" (with an explicit + // transaction) is called internally by the plugin to set a global + // property during the initialization of the database. (TODO: + // Could be replaced by the version with an implicit transaction + // to avoid code redundancy). + if (db.GetDialect() == Dialect_SQLite) { Query query("INSERT OR REPLACE INTO GlobalProperties VALUES (${property}, ${value})", false); query.SetType("property", ValueType_Integer64); query.SetType("value", ValueType_Utf8String); - std::auto_ptr statement(db.Compile(query)); + std::unique_ptr statement(db.Compile(query)); Dictionary args; args.SetIntegerValue("property", static_cast(property)); @@ -135,7 +142,7 @@ Query query("DELETE FROM GlobalProperties WHERE property=${property}", false); query.SetType("property", ValueType_Integer64); - std::auto_ptr statement(db.Compile(query)); + std::unique_ptr statement(db.Compile(query)); Dictionary args; args.SetIntegerValue("property", static_cast(property)); @@ -148,7 +155,7 @@ query.SetType("property", ValueType_Integer64); query.SetType("value", ValueType_Utf8String); - std::auto_ptr statement(db.Compile(query)); + std::unique_ptr statement(db.Compile(query)); Dictionary args; args.SetIntegerValue("property", static_cast(property)); @@ -164,6 +171,11 @@ Orthanc::GlobalProperty property, const std::string& utf8) { + // This version of "SetGlobalProperty()" (without an explicit + // transaction) is called by Orthanc during its execution. Orthanc + // manages the transaction at a higher level, but this transaction + // is always present. + if (manager.GetDialect() == Dialect_SQLite) { DatabaseManager::CachedStatement statement( diff -Nru orthanc-mysql-2.0/Framework/Plugins/GlobalProperties.h orthanc-mysql-3.0/Framework/Plugins/GlobalProperties.h --- orthanc-mysql-2.0/Framework/Plugins/GlobalProperties.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/GlobalProperties.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,7 +23,40 @@ #include "../Common/DatabaseManager.h" -#include + +namespace Orthanc +{ + /** + * The enum "GlobalProperty" below must use same values as in the + * source code of the Orthanc server: + * https://hg.orthanc-server.com/orthanc/file/default/OrthancServer/Sources/ServerEnumerations.h + **/ + + enum GlobalProperty + { + GlobalProperty_DatabaseSchemaVersion = 1, // Unused in the Orthanc core as of Orthanc 0.9.5 + GlobalProperty_FlushSleep = 2, + GlobalProperty_AnonymizationSequence = 3, + GlobalProperty_JobsRegistry = 5, + GlobalProperty_GetTotalSizeIsFast = 6, // New in Orthanc 1.5.2 + GlobalProperty_Modalities = 20, // New in Orthanc 1.5.0 + GlobalProperty_Peers = 21, // New in Orthanc 1.5.0 + + // Reserved values for internal use by the database plugins + GlobalProperty_DatabasePatchLevel = 4, + GlobalProperty_DatabaseInternal0 = 10, + GlobalProperty_DatabaseInternal1 = 11, + GlobalProperty_DatabaseInternal2 = 12, + GlobalProperty_DatabaseInternal3 = 13, + GlobalProperty_DatabaseInternal4 = 14, + GlobalProperty_DatabaseInternal5 = 15, + GlobalProperty_DatabaseInternal6 = 16, + GlobalProperty_DatabaseInternal7 = 17, + GlobalProperty_DatabaseInternal8 = 18, + GlobalProperty_DatabaseInternal9 = 19 + }; +} + namespace OrthancDatabases { diff -Nru orthanc-mysql-2.0/Framework/Plugins/IndexBackend.cpp orthanc-mysql-3.0/Framework/Plugins/IndexBackend.cpp --- orthanc-mysql-2.0/Framework/Plugins/IndexBackend.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/IndexBackend.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -21,15 +21,15 @@ #include "IndexBackend.h" +#include "../../Resources/Orthanc/Databases/ISqlLookupFormatter.h" #include "../Common/BinaryStringValue.h" #include "../Common/Integer64Value.h" #include "../Common/Utf8StringValue.h" #include "GlobalProperties.h" -#include -#include -#include -#include +#include // For std::unique_ptr<> +#include +#include namespace OrthancDatabases @@ -693,7 +693,7 @@ uint64_t IndexBackend::GetResourceCount(OrthancPluginResourceType resourceType) { - std::auto_ptr statement; + std::unique_ptr statement; switch (manager_.GetDialect()) { @@ -758,7 +758,7 @@ uint64_t IndexBackend::GetTotalCompressedSize() { - std::auto_ptr statement; + std::unique_ptr statement; // NB: "COALESCE" is used to replace "NULL" by "0" if the number of rows is empty @@ -795,7 +795,7 @@ uint64_t IndexBackend::GetTotalUncompressedSize() { - std::auto_ptr statement; + std::unique_ptr statement; // NB: "COALESCE" is used to replace "NULL" by "0" if the number of rows is empty @@ -1010,7 +1010,7 @@ OrthancPluginIdentifierConstraint constraint, const char* value) { - std::auto_ptr statement; + std::unique_ptr statement; std::string header = "SELECT d.id FROM DicomIdentifiers AS d, Resources AS r WHERE " @@ -1466,7 +1466,7 @@ // For unit testing only! uint64_t IndexBackend::GetResourcesCount() { - std::auto_ptr statement; + std::unique_ptr statement; switch (manager_.GetDialect()) { @@ -1502,7 +1502,7 @@ // For unit testing only! uint64_t IndexBackend::GetUnprotectedPatientsCount() { - std::auto_ptr statement; + std::unique_ptr statement; switch (manager_.GetDialect()) { @@ -1739,9 +1739,9 @@ args.SetUtf8Value(name, tags[i].value); std::string insert = ("(" + boost::lexical_cast(tags[i].resource) + ", " + - boost::lexical_cast(tags[i].group) + ", " + - boost::lexical_cast(tags[i].element) + ", " + - "${" + name + "})"); + boost::lexical_cast(tags[i].group) + ", " + + boost::lexical_cast(tags[i].element) + ", " + + "${" + name + "})"); if (sql.empty()) { @@ -1787,7 +1787,7 @@ std::string insert = ("(" + boost::lexical_cast(metadata[i].resource) + ", " + boost::lexical_cast(metadata[i].metadata) + ", " + - "${" + name + "})"); + "${" + name + "})"); std::string remove = ("(id=" + boost::lexical_cast(metadata[i].resource) + " AND type=" + boost::lexical_cast(metadata[i].metadata) @@ -1951,4 +1951,108 @@ statement.Execute(args); } } + + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // New primitive since Orthanc 1.5.4 + bool IndexBackend::LookupResourceAndParent(int64_t& id, + OrthancPluginResourceType& type, + std::string& parentPublicId, + const char* publicId) + { + DatabaseManager::CachedStatement statement( + STATEMENT_FROM_HERE, manager_, + "SELECT resource.internalId, resource.resourceType, parent.publicId " + "FROM Resources AS resource LEFT JOIN Resources parent ON parent.internalId=resource.parentId " + "WHERE resource.publicId=${id}"); + + statement.SetParameterType("id", ValueType_Utf8String); + + Dictionary args; + args.SetUtf8Value("id", publicId); + + statement.Execute(args); + + if (statement.IsDone()) + { + return false; + } + else + { + if (statement.GetResultFieldsCount() != 3) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + statement.SetResultFieldType(0, ValueType_Integer64); + statement.SetResultFieldType(1, ValueType_Integer64); + statement.SetResultFieldType(2, ValueType_Utf8String); + + id = ReadInteger64(statement, 0); + type = static_cast(ReadInteger32(statement, 1)); + + const IValue& value = statement.GetResultField(2); + + switch (value.GetType()) + { + case ValueType_Null: + parentPublicId.clear(); + break; + + case ValueType_Utf8String: + parentPublicId = dynamic_cast(value).GetContent(); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + assert((statement.Next(), statement.IsDone())); + return true; + } + } +# endif +#endif + + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // New primitive since Orthanc 1.5.4 + void IndexBackend::GetAllMetadata(std::map& result, + int64_t id) + { + DatabaseManager::CachedStatement statement( + STATEMENT_FROM_HERE, manager_, + "SELECT type, value FROM Metadata WHERE id=${id}"); + + statement.SetReadOnly(true); + statement.SetParameterType("id", ValueType_Integer64); + + Dictionary args; + args.SetIntegerValue("id", id); + + statement.Execute(args); + + result.clear(); + + if (!statement.IsDone()) + { + if (statement.GetResultFieldsCount() != 2) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + statement.SetResultFieldType(0, ValueType_Integer64); + statement.SetResultFieldType(1, ValueType_Utf8String); + + while (!statement.IsDone()) + { + result[ReadInteger32(statement, 0)] = ReadString(statement, 1); + statement.Next(); + } + } + } +# endif +#endif } diff -Nru orthanc-mysql-2.0/Framework/Plugins/IndexBackend.h orthanc-mysql-3.0/Framework/Plugins/IndexBackend.h --- orthanc-mysql-2.0/Framework/Plugins/IndexBackend.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/IndexBackend.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -283,5 +283,23 @@ int32_t metadata); virtual void TagMostRecentPatient(int64_t patient); + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // New primitive since Orthanc 1.5.4 + virtual bool LookupResourceAndParent(int64_t& id, + OrthancPluginResourceType& type, + std::string& parentPublicId, + const char* publicId); +# endif +#endif + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // New primitive since Orthanc 1.5.4 + virtual void GetAllMetadata(std::map& result, + int64_t id); +# endif +#endif }; } diff -Nru orthanc-mysql-2.0/Framework/Plugins/IndexUnitTests.h orthanc-mysql-3.0/Framework/Plugins/IndexUnitTests.h --- orthanc-mysql-2.0/Framework/Plugins/IndexUnitTests.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/IndexUnitTests.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -22,17 +22,34 @@ #pragma once #include "../Common/ImplicitTransaction.h" +#include "GlobalProperties.h" + +#include // For std::unique_ptr<> #include -#include #include #include -static std::auto_ptr expectedAttachment; +namespace Orthanc +{ + /** + * Mock enumeration inspired from the source code of Orthanc... only + * for use in the unit tests! + * https://hg.orthanc-server.com/orthanc/file/default/OrthancServer/Sources/ServerEnumerations.h + **/ + enum MetadataType + { + MetadataType_ModifiedFrom, + MetadataType_LastUpdate + }; +} + + +static std::unique_ptr expectedAttachment; static std::list expectedDicomTags; -static std::auto_ptr expectedExported; +static std::unique_ptr expectedExported; static void CheckAttachment(const OrthancPluginAttachment& attachment) { diff -Nru orthanc-mysql-2.0/Framework/Plugins/OrthancCppDatabasePlugin.h orthanc-mysql-3.0/Framework/Plugins/OrthancCppDatabasePlugin.h --- orthanc-mysql-2.0/Framework/Plugins/OrthancCppDatabasePlugin.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/OrthancCppDatabasePlugin.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -37,8 +37,9 @@ #endif -#include -#include +#include "../../Resources/Orthanc/Databases/DatabaseConstraint.h" + +#include @@ -82,7 +83,8 @@ AllowedAnswers_DicomTag, AllowedAnswers_ExportedResource, AllowedAnswers_MatchingResource, - AllowedAnswers_String + AllowedAnswers_String, + AllowedAnswers_Metadata }; OrthancPluginContext* context_; @@ -534,6 +536,23 @@ virtual int64_t GetLastChangeIndex() = 0; virtual void TagMostRecentPatient(int64_t patientId) = 0; + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // NB: "parentPublicId" must be cleared if the resource has no parent + virtual bool LookupResourceAndParent(int64_t& id, + OrthancPluginResourceType& type, + std::string& parentPublicId, + const char* publicId) = 0; +# endif +#endif + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + virtual void GetAllMetadata(std::map& result, + int64_t id) = 0; +# endif +#endif }; @@ -1650,6 +1669,77 @@ } +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // New primitive since Orthanc 1.5.4 + static OrthancPluginErrorCode GetAllMetadata(OrthancPluginDatabaseContext* context, + void* payload, + int64_t resourceId) + { + IDatabaseBackend* backend = reinterpret_cast(payload); + backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_Metadata); + + try + { + std::map result; + backend->GetAllMetadata(result, resourceId); + + for (std::map::const_iterator + it = result.begin(); it != result.end(); ++it) + { + OrthancPluginDatabaseAnswerMetadata(backend->GetOutput().context_, + backend->GetOutput().database_, + resourceId, it->first, it->second.c_str()); + } + + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH + } +# endif +#endif + + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // New primitive since Orthanc 1.5.4 + static OrthancPluginErrorCode LookupResourceAndParent(OrthancPluginDatabaseContext* context, + uint8_t* isExisting, + int64_t* id, + OrthancPluginResourceType* type, + void* payload, + const char* publicId) + { + IDatabaseBackend* backend = reinterpret_cast(payload); + backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_String); + + try + { + std::string parent; + if (backend->LookupResourceAndParent(*id, *type, parent, publicId)) + { + *isExisting = 1; + + if (!parent.empty()) + { + OrthancPluginDatabaseAnswerString(backend->GetOutput().context_, + backend->GetOutput().database_, + parent.c_str()); + } + } + else + { + *isExisting = 0; + } + + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH + } +# endif +#endif + + public: /** * Register a custom database back-end written in C++. @@ -1741,20 +1831,30 @@ { extensions.createInstance = CreateInstance; // Fast creation of resources } - - performanceWarning = false; #endif +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) + // Optimizations brought by Orthanc 1.5.4 + extensions.lookupResourceAndParent = LookupResourceAndParent; + extensions.getAllMetadata = GetAllMetadata; + performanceWarning = false; +# endif +#endif + if (performanceWarning) { char info[1024]; sprintf(info, "Performance warning: The database index plugin was compiled " "against an old version of the Orthanc SDK (%d.%d.%d): " - "Consider upgrading to version 1.5.2 of the Orthanc SDK", + "Consider upgrading to version %d.%d.%d of the Orthanc SDK", ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, - ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER, + ORTHANC_OPTIMAL_VERSION_MAJOR, + ORTHANC_OPTIMAL_VERSION_MINOR, + ORTHANC_OPTIMAL_VERSION_REVISION); OrthancPluginLogWarning(context, info); } diff -Nru orthanc-mysql-2.0/Framework/Plugins/PluginInitialization.cpp orthanc-mysql-3.0/Framework/Plugins/PluginInitialization.cpp --- orthanc-mysql-2.0/Framework/Plugins/PluginInitialization.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/PluginInitialization.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -22,10 +22,10 @@ #include "PluginInitialization.h" #include "../Common/ImplicitTransaction.h" +#include "../../Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h" -#include -#include -#include +#include +#include namespace OrthancDatabases @@ -45,7 +45,12 @@ const std::string& dbms, bool isIndex) { +#if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 7, 2) + Orthanc::Logging::InitializePluginContext(context); +#else Orthanc::Logging::Initialize(context); +#endif + OrthancPlugins::SetGlobalContext(context); ImplicitTransaction::SetErrorOnDoubleExecution(false); @@ -68,6 +73,13 @@ if (OrthancPluginCheckVersionAdvanced(context, 1, 4, 0) == 1) { ImplicitTransaction::SetErrorOnDoubleExecution(true); + } + + if (OrthancPluginCheckVersionAdvanced(context, + ORTHANC_OPTIMAL_VERSION_MAJOR, + ORTHANC_OPTIMAL_VERSION_MINOR, + ORTHANC_OPTIMAL_VERSION_REVISION) == 1) + { isOptimal = true; } @@ -110,9 +122,12 @@ int minor = boost::lexical_cast(tokens[1]); int revision = boost::lexical_cast(tokens[2]); - isOptimal = (major > 1 || - (major == 1 && minor > 4) || - (major == 1 && minor == 4 && revision >= 0)); + isOptimal = (major > ORTHANC_OPTIMAL_VERSION_MAJOR || + (major == ORTHANC_OPTIMAL_VERSION_MAJOR && + minor > ORTHANC_OPTIMAL_VERSION_MINOR) || + (major == ORTHANC_OPTIMAL_VERSION_MAJOR && + minor == ORTHANC_OPTIMAL_VERSION_MINOR && + revision >= ORTHANC_OPTIMAL_VERSION_REVISION)); } } @@ -121,8 +136,11 @@ { LOG(WARNING) << "Performance warning in " << dbms << " index: Your version of Orthanc (" - << context->orthancVersion << ") should be upgraded to 1.5.2 " - << "to benefit from best performance"; + << context->orthancVersion << ") should be upgraded to " + << ORTHANC_OPTIMAL_VERSION_MAJOR << "." + << ORTHANC_OPTIMAL_VERSION_MINOR << "." + << ORTHANC_OPTIMAL_VERSION_REVISION + << " to benefit from best performance"; } diff -Nru orthanc-mysql-2.0/Framework/Plugins/PluginInitialization.h orthanc-mysql-3.0/Framework/Plugins/PluginInitialization.h --- orthanc-mysql-2.0/Framework/Plugins/PluginInitialization.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/PluginInitialization.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License diff -Nru orthanc-mysql-2.0/Framework/Plugins/StorageBackend.cpp orthanc-mysql-3.0/Framework/Plugins/StorageBackend.cpp --- orthanc-mysql-2.0/Framework/Plugins/StorageBackend.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/StorageBackend.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -28,7 +28,8 @@ #include "../../Framework/Common/BinaryStringValue.h" #include "../../Framework/Common/FileValue.h" -#include +#include // For std::unique_ptr<> +#include #define ORTHANC_PLUGINS_DATABASE_CATCH \ @@ -208,7 +209,7 @@ static OrthancPluginContext* context_ = NULL; - static std::auto_ptr backend_; + static std::unique_ptr backend_; static OrthancPluginErrorCode StorageCreate(const char* uuid, diff -Nru orthanc-mysql-2.0/Framework/Plugins/StorageBackend.h orthanc-mysql-3.0/Framework/Plugins/StorageBackend.h --- orthanc-mysql-2.0/Framework/Plugins/StorageBackend.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Framework/Plugins/StorageBackend.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -38,7 +38,7 @@ const std::string& content); public: - StorageBackend(IDatabaseFactory* factory); + explicit StorageBackend(IDatabaseFactory* factory); virtual ~StorageBackend() { diff -Nru orthanc-mysql-2.0/.hg_archival.txt orthanc-mysql-3.0/.hg_archival.txt --- orthanc-mysql-2.0/.hg_archival.txt 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/.hg_archival.txt 2020-12-16 15:23:36.000000000 +0000 @@ -1,6 +1,6 @@ repo: 7cea966b682978aa285eb9b3a7a9cff81df464b3 -node: fbdef056271745932b1ea1b632c20a43f92a3b14 -branch: OrthancMySQL-2.0 +node: 206f8c616b803bbf2a48fb9b85990883e672d71f +branch: OrthancMySQL-3.0 latesttag: null -latesttagdistance: 103 -changessincelatesttag: 113 +latesttagdistance: 170 +changessincelatesttag: 186 diff -Nru orthanc-mysql-2.0/MySQL/CMakeLists.txt orthanc-mysql-3.0/MySQL/CMakeLists.txt --- orthanc-mysql-2.0/MySQL/CMakeLists.txt 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/CMakeLists.txt 2020-12-16 15:23:36.000000000 +0000 @@ -1,19 +1,24 @@ cmake_minimum_required(VERSION 2.8) project(OrthancMySQL) -set(ORTHANC_PLUGIN_VERSION "2.0") +set(ORTHANC_PLUGIN_VERSION "3.0") + +set(ORTHANC_OPTIMAL_VERSION_MAJOR 1) +set(ORTHANC_OPTIMAL_VERSION_MINOR 5) +set(ORTHANC_OPTIMAL_VERSION_REVISION 4) if (ORTHANC_PLUGIN_VERSION STREQUAL "mainline") set(ORTHANC_FRAMEWORK_VERSION "mainline") set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg") else() - set(ORTHANC_FRAMEWORK_VERSION "1.5.2") + set(ORTHANC_FRAMEWORK_VERSION "4a3ba4bf4ba7") # This is Orthanc Framework pre-1.8.2 (includes a fix for OpenSSL on MSVC) set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web") endif() include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesPluginParameters.cmake) set(ENABLE_MYSQL_BACKEND ON) +set(OPENSSL_STATIC_VERSION "1.1.1" CACHE STRING "Force the use of OpenSSL 1.1.1" FORCE) include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesPluginConfiguration.cmake) @@ -21,7 +26,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") execute_process( COMMAND - ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py + ${PYTHON_EXECUTABLE} ${ORTHANC_FRAMEWORK_ROOT}/../Resources/WindowsResources.py ${ORTHANC_PLUGIN_VERSION} "MySQL storage area plugin" OrthancMySQLStorage.dll "MySQL as a database back-end to Orthanc (storage area)" ERROR_VARIABLE Failure @@ -34,7 +39,7 @@ execute_process( COMMAND - ${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py + ${PYTHON_EXECUTABLE} ${ORTHANC_FRAMEWORK_ROOT}/../Resources/WindowsResources.py ${ORTHANC_PLUGIN_VERSION} "MySQL index plugin" OrthancMySQLIndex.dll "MySQL as a database back-end to Orthanc (index)" ERROR_VARIABLE Failure @@ -56,6 +61,12 @@ MYSQL_CREATE_INSTANCE ${CMAKE_SOURCE_DIR}/Plugins/CreateInstance.sql ) +add_custom_target( + AutogeneratedTarget + DEPENDS + ${AUTOGENERATED_SOURCES} + ) + add_library(OrthancMySQLIndex SHARED ${INDEX_RESOURCES} ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/PluginInitialization.cpp @@ -66,6 +77,8 @@ ${AUTOGENERATED_SOURCES} ) +add_dependencies(OrthancMySQLIndex AutogeneratedTarget) + add_library(OrthancMySQLStorage SHARED ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/PluginInitialization.cpp ${STORAGE_RESOURCES} @@ -76,6 +89,8 @@ ${AUTOGENERATED_SOURCES} ) +add_dependencies(OrthancMySQLStorage AutogeneratedTarget) + message("Setting the version of the libraries to ${ORTHANC_PLUGIN_VERSION}") add_definitions( @@ -111,6 +126,8 @@ ${AUTOGENERATED_SOURCES} ) +add_dependencies(UnitTests AutogeneratedTarget) + target_link_libraries(UnitTests ${GOOGLE_TEST_LIBRARIES}) set_target_properties(UnitTests PROPERTIES COMPILE_FLAGS -DORTHANC_ENABLE_LOGGING_PLUGIN=0 diff -Nru orthanc-mysql-2.0/MySQL/NEWS orthanc-mysql-3.0/MySQL/NEWS --- orthanc-mysql-2.0/MySQL/NEWS 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/NEWS 2020-12-16 15:23:36.000000000 +0000 @@ -2,6 +2,26 @@ =============================== +Release 3.0 (2020-12-16) +======================== + +* Report issue/solution and prevent the start of Orthanc if the MySQL user is + not allowed to run the "CREATE TRIGGER" command (missing "SUPER" privilege) +* Implementation of new extensions: LookupResourceAndParent and GetAllMetadata +* Added an advisory lock to avoid race conditions during database setup +* Added "MaximumConnectionRetries" & "ConnectionRetryInterval" to configure + the retries when connecting to the DB at startup +* Support of dynamic linking against the system-wide Orthanc framework library +* Added support for TLS connections: 3 new options: + - "EnableSsl" (false by default) + - "SslVerifyServerCertificates" (true by default - inactive if EnableSsl if false) + - "SslCACertificates" (default value is "HttpsCACertificates" from global + Orthanc configuration) +* Upgraded dependencies for static builds (notably on Windows and LSB): + - openssl 1.1.1g + - mariadb-connector-c 3.1.11 + + Release 2.0 (2019-01-23) ======================== diff -Nru orthanc-mysql-2.0/MySQL/Plugins/CreateInstance.sql orthanc-mysql-3.0/MySQL/Plugins/CreateInstance.sql --- orthanc-mysql-2.0/MySQL/Plugins/CreateInstance.sql 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/CreateInstance.sql 2020-12-16 15:23:36.000000000 +0000 @@ -1,3 +1,5 @@ +DROP PROCEDURE IF EXISTS CreateInstance; + CREATE PROCEDURE CreateInstance( IN patient TEXT, IN study TEXT, diff -Nru orthanc-mysql-2.0/MySQL/Plugins/GetLastChangeIndex.sql orthanc-mysql-3.0/MySQL/Plugins/GetLastChangeIndex.sql --- orthanc-mysql-2.0/MySQL/Plugins/GetLastChangeIndex.sql 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/GetLastChangeIndex.sql 2020-12-16 15:23:36.000000000 +0000 @@ -1,13 +1,17 @@ -CREATE TABLE GlobalIntegers( +CREATE TABLE IF NOT EXISTS GlobalIntegers( property INTEGER PRIMARY KEY, value BIGINT ); +DELETE FROM GlobalIntegers WHERE property = 0; + INSERT INTO GlobalIntegers SELECT 0, COALESCE(MAX(seq), 0) FROM Changes; +DROP TRIGGER IF EXISTS ChangeAdded; + CREATE TRIGGER ChangeAdded AFTER INSERT ON Changes FOR EACH ROW diff -Nru orthanc-mysql-2.0/MySQL/Plugins/IndexPlugin.cpp orthanc-mysql-3.0/MySQL/Plugins/IndexPlugin.cpp --- orthanc-mysql-2.0/MySQL/Plugins/IndexPlugin.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/IndexPlugin.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,11 +23,12 @@ #include "../../Framework/MySQL/MySQLDatabase.h" #include "../../Framework/Plugins/PluginInitialization.h" -#include -#include -#include +#include // For std::unique_ptr<> +#include +#include +#include -static std::auto_ptr backend_; +static std::unique_ptr backend_; extern "C" @@ -64,7 +65,7 @@ try { - OrthancDatabases::MySQLParameters parameters(mysql); + OrthancDatabases::MySQLParameters parameters(mysql, configuration); /* Create the database back-end */ backend_.reset(new OrthancDatabases::MySQLIndex(parameters)); diff -Nru orthanc-mysql-2.0/MySQL/Plugins/MySQLDefinitions.h orthanc-mysql-3.0/MySQL/Plugins/MySQLDefinitions.h --- orthanc-mysql-2.0/MySQL/Plugins/MySQLDefinitions.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/MySQLDefinitions.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,49 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include + + +/** + * This advisory lock is used if the "Lock" option is set to "true", + * in order to prevent the execution of two PostgreSQL index plugins + * on the same database. + **/ +static const char* const MYSQL_LOCK_INDEX = "orthanc_index_lock"; + + +/** + * This advisory lock is used if the "Lock" option is set to "true", + * in order to prevent the execution of two PostgreSQL storage area + * plugins on the same database. + **/ +static const char* const MYSQL_LOCK_STORAGE = "orthanc_storage_lock"; + + +/** + * Transient advisory lock to protect the setup of the database, + * because concurrent statements like "CREATE TABLE" are not protected + * by transactions. + * https://groups.google.com/d/msg/orthanc-users/yV3LSTh_TjI/h3PRApJFBAAJ + **/ +static const char* const MYSQL_LOCK_DATABASE_SETUP = "orthanc_setup_lock"; diff -Nru orthanc-mysql-2.0/MySQL/Plugins/MySQLIndex.cpp orthanc-mysql-3.0/MySQL/Plugins/MySQLIndex.cpp --- orthanc-mysql-2.0/MySQL/Plugins/MySQLIndex.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/MySQLIndex.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -24,16 +24,28 @@ #include "../../Framework/Plugins/GlobalProperties.h" #include "../../Framework/MySQL/MySQLDatabase.h" #include "../../Framework/MySQL/MySQLTransaction.h" +#include "MySQLDefinitions.h" #include // Auto-generated file -#include -#include +#include // For std::unique_ptr<> +#include +#include #include namespace OrthancDatabases { + static void ThrowCannotCreateTrigger() + { + LOG(ERROR) << "The MySQL user is not allowed to create triggers => 2 possible solutions:"; + LOG(ERROR) << " 1- Give the SUPER privilege to the MySQL database user, or"; + LOG(ERROR) << " 2- Run \"set global log_bin_trust_function_creators=1;\" as MySQL root user."; + LOG(ERROR) << "Once you are done, drop and recreate the MySQL database"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, + "Need to fix the MySQL permissions for \"CREATE TRIGGER\""); + } + IDatabase* MySQLIndex::OpenInternal() { uint32_t expectedVersion = 6; @@ -66,114 +78,193 @@ MySQLDatabase::ClearDatabase(parameters_); } - std::auto_ptr db(new MySQLDatabase(parameters_)); + std::unique_ptr db(new MySQLDatabase(parameters_)); db->Open(); - db->Execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE", false); - if (parameters_.HasLock()) - { - db->AdvisoryLock(42 /* some arbitrary constant */); - } - { - MySQLTransaction t(*db); + MySQLDatabase::TransientAdvisoryLock lock(*db, MYSQL_LOCK_DATABASE_SETUP); - db->Execute("ALTER DATABASE " + parameters_.GetDatabase() + - " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", false); - - if (!db->DoesTableExist(t, "Resources")) + /** + * In a first transaction, we create the tables. Such a + * transaction cannot be rollback: "The CREATE TABLE statement + * in InnoDB is processed as a single transaction. This means + * that a ROLLBACK from the user does not undo CREATE TABLE + * statements the user made during that transaction." + * https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html + * + * As a consequence, we delay the initial population of the + * tables in a sequence of transactions below. This solves the + * error message "MySQL plugin is incompatible with database + * schema version: 0" that was reported in the forum: + * https://groups.google.com/d/msg/orthanc-users/OCFFkm1qm0k/Mbroy8VWAQAJ + **/ { - std::string query; + MySQLTransaction t(*db); + + db->Execute("ALTER DATABASE " + parameters_.GetDatabase() + + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", false); - Orthanc::EmbeddedResources::GetFileResource - (query, Orthanc::EmbeddedResources::MYSQL_PREPARE_INDEX); - db->Execute(query, true); + // This is the first table to be created + if (!db->DoesTableExist(t, "GlobalProperties")) + { + std::string query; + + Orthanc::EmbeddedResources::GetFileResource + (query, Orthanc::EmbeddedResources::MYSQL_PREPARE_INDEX); + db->Execute(query, true); + } - SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabaseSchemaVersion, expectedVersion); - SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, 1); + t.Commit(); } - if (!db->DoesTableExist(t, "Resources")) - { - LOG(ERROR) << "Corrupted MySQL database"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } + /** + * This is the sequence of transactions that initially populate + * the database. WARNING - As table creation cannot be rollback, + * don't forget to add "IF NOT EXISTS" if some table must be + * created below this point (in order to recover from failed + * transaction). + **/ int version = 0; - if (!LookupGlobalIntegerProperty(version, *db, t, Orthanc::GlobalProperty_DatabaseSchemaVersion) || - version != 6) + { - LOG(ERROR) << "MySQL plugin is incompatible with database schema version: " << version; - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); + MySQLTransaction t(*db); + + // This is the last table to be created + if (!db->DoesTableExist(t, "PatientRecyclingOrder")) + { + LOG(ERROR) << "Corrupted MySQL database"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + // This is the last item to be created + if (!db->DoesTriggerExist(t, "PatientAdded")) + { + ThrowCannotCreateTrigger(); + } + + if (!LookupGlobalIntegerProperty(version, *db, t, Orthanc::GlobalProperty_DatabaseSchemaVersion)) + { + SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabaseSchemaVersion, expectedVersion); + SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, 1); + version = expectedVersion; + } + + if (version != 6) + { + LOG(ERROR) << "MySQL plugin is incompatible with database schema version: " << version; + throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); + } + + t.Commit(); } - int revision; - if (!LookupGlobalIntegerProperty(revision, *db, t, Orthanc::GlobalProperty_DatabasePatchLevel)) + int revision = 0; + { - revision = 1; - SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, revision); + MySQLTransaction t(*db); + + if (!LookupGlobalIntegerProperty(revision, *db, t, Orthanc::GlobalProperty_DatabasePatchLevel)) + { + revision = 1; + SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, revision); + } + + t.Commit(); } if (revision == 1) { + MySQLTransaction t(*db); + // The serialization of jobs as a global property can lead to // very long values => switch to the LONGTEXT type that can // store up to 4GB: // https://stackoverflow.com/a/13932834/881731 db->Execute("ALTER TABLE GlobalProperties MODIFY value LONGTEXT", false); - + revision = 2; SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, revision); + + t.Commit(); } if (revision == 2) - { + { + MySQLTransaction t(*db); + // Install the "GetLastChangeIndex" extension std::string query; Orthanc::EmbeddedResources::GetFileResource (query, Orthanc::EmbeddedResources::MYSQL_GET_LAST_CHANGE_INDEX); db->Execute(query, true); + + if (!db->DoesTriggerExist(t, "ChangeAdded")) + { + ThrowCannotCreateTrigger(); + } revision = 3; SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, revision); - } + t.Commit(); + } + if (revision == 3) { + MySQLTransaction t(*db); + // Reconfiguration of "Metadata" from TEXT type (up to 64KB) // to the LONGTEXT type (up to 4GB). This might be important // for applications such as the Osimis Web viewer that stores // large amount of metadata. // http://book.orthanc-server.com/faq/features.html#central-registry-of-metadata-and-attachments db->Execute("ALTER TABLE Metadata MODIFY value LONGTEXT", false); - + revision = 4; SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, revision); - } + t.Commit(); + } + if (revision == 4) { + MySQLTransaction t(*db); + // Install the "CreateInstance" extension std::string query; - + Orthanc::EmbeddedResources::GetFileResource (query, Orthanc::EmbeddedResources::MYSQL_CREATE_INSTANCE); db->Execute(query, true); - + revision = 5; SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, revision); - } + t.Commit(); + } + if (revision != 5) { LOG(ERROR) << "MySQL plugin is incompatible with database schema revision: " << revision; throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); } + } - t.Commit(); + /** + * WARNING: This lock must be acquired after + * "MYSQL_LOCK_DATABASE_SETUP" is released. Indeed, in MySQL < + * 5.7, it is impossible to acquire more than one lock at a time, + * as calling "SELECT GET_LOCK()" releases all the + * previously-acquired locks. + * https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html + **/ + if (parameters_.HasLock()) + { + db->AdvisoryLock(MYSQL_LOCK_INDEX); } return db.release(); diff -Nru orthanc-mysql-2.0/MySQL/Plugins/MySQLIndex.h orthanc-mysql-3.0/MySQL/Plugins/MySQLIndex.h --- orthanc-mysql-2.0/MySQL/Plugins/MySQLIndex.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/MySQLIndex.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -49,6 +49,12 @@ { return that_.OpenInternal(); } + + virtual void GetConnectionRetriesParameters(unsigned int& maxConnectionRetries, unsigned int& connectionRetryInterval) + { + maxConnectionRetries = that_.parameters_.GetMaxConnectionRetries(); + connectionRetryInterval = that_.parameters_.GetConnectionRetryInterval(); + } }; OrthancPluginContext* context_; diff -Nru orthanc-mysql-2.0/MySQL/Plugins/MySQLStorageArea.cpp orthanc-mysql-3.0/MySQL/Plugins/MySQLStorageArea.cpp --- orthanc-mysql-2.0/MySQL/Plugins/MySQLStorageArea.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/MySQLStorageArea.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,8 +23,10 @@ #include "../../Framework/MySQL/MySQLDatabase.h" #include "../../Framework/MySQL/MySQLTransaction.h" +#include "MySQLDefinitions.h" -#include +#include // For std::unique_ptr<> +#include #include @@ -33,16 +35,12 @@ { IDatabase* MySQLStorageArea::OpenInternal() { - std::auto_ptr db(new MySQLDatabase(parameters_)); + std::unique_ptr db(new MySQLDatabase(parameters_)); db->Open(); - if (parameters_.HasLock()) - { - db->AdvisoryLock(43 /* some arbitrary constant */); - } - { + MySQLDatabase::TransientAdvisoryLock lock(*db, MYSQL_LOCK_DATABASE_SETUP); MySQLTransaction t(*db); int64_t size; @@ -74,6 +72,19 @@ t.Commit(); } + /** + * WARNING: This lock must be acquired after + * "MYSQL_LOCK_DATABASE_SETUP" is released. Indeed, in MySQL < + * 5.7, it is impossible to acquire more than one lock at a time, + * as calling "SELECT GET_LOCK()" releases all the + * previously-acquired locks. + * https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html + **/ + if (parameters_.HasLock()) + { + db->AdvisoryLock(MYSQL_LOCK_STORAGE); + } + return db.release(); } diff -Nru orthanc-mysql-2.0/MySQL/Plugins/MySQLStorageArea.h orthanc-mysql-3.0/MySQL/Plugins/MySQLStorageArea.h --- orthanc-mysql-2.0/MySQL/Plugins/MySQLStorageArea.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/MySQLStorageArea.h 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -36,30 +36,36 @@ MySQLStorageArea& that_; public: - Factory(MySQLStorageArea& that) : + explicit Factory(MySQLStorageArea& that) : that_(that) { } - virtual Dialect GetDialect() const + virtual Dialect GetDialect() const ORTHANC_OVERRIDE { return Dialect_MySQL; } - virtual IDatabase* Open() + virtual IDatabase* Open() ORTHANC_OVERRIDE { return that_.OpenInternal(); } + + virtual void GetConnectionRetriesParameters(unsigned int& maxConnectionRetries, + unsigned int& connectionRetryInterval) ORTHANC_OVERRIDE + { + maxConnectionRetries = that_.parameters_.GetMaxConnectionRetries(); + connectionRetryInterval = that_.parameters_.GetConnectionRetryInterval(); + } }; - OrthancPluginContext* context_; MySQLParameters parameters_; bool clearAll_; IDatabase* OpenInternal(); public: - MySQLStorageArea(const MySQLParameters& parameters); + explicit MySQLStorageArea(const MySQLParameters& parameters); void SetClearAll(bool clear) { diff -Nru orthanc-mysql-2.0/MySQL/Plugins/StoragePlugin.cpp orthanc-mysql-3.0/MySQL/Plugins/StoragePlugin.cpp --- orthanc-mysql-2.0/MySQL/Plugins/StoragePlugin.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/Plugins/StoragePlugin.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -23,9 +23,9 @@ #include "../../Framework/MySQL/MySQLDatabase.h" #include "../../Framework/Plugins/PluginInitialization.h" -#include -#include -#include +#include +#include +#include extern "C" @@ -62,7 +62,7 @@ try { - OrthancDatabases::MySQLParameters parameters(mysql); + OrthancDatabases::MySQLParameters parameters(mysql, configuration); OrthancDatabases::StorageBackend::Register (context, new OrthancDatabases::MySQLStorageArea(parameters)); } diff -Nru orthanc-mysql-2.0/MySQL/UnitTests/UnitTestsMain.cpp orthanc-mysql-3.0/MySQL/UnitTests/UnitTestsMain.cpp --- orthanc-mysql-2.0/MySQL/UnitTests/UnitTestsMain.cpp 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/MySQL/UnitTests/UnitTestsMain.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License @@ -31,9 +31,10 @@ #include "../../Framework/MySQL/MySQLTransaction.h" #include "../../Framework/Plugins/IndexUnitTests.h" -#include -#include -#include +#include // For std::unique_ptr<> +#include +#include +#include #include @@ -63,13 +64,82 @@ } +TEST(MySQL, Lock2) +{ + OrthancDatabases::MySQLDatabase::ClearDatabase(globalParameters_); + + OrthancDatabases::MySQLDatabase db1(globalParameters_); + db1.Open(); + + ASSERT_FALSE(db1.ReleaseAdvisoryLock("mylock")); // lock counter = 0 + ASSERT_TRUE(db1.AcquireAdvisoryLock("mylock")); // lock counter = 1 + + // OK, as this is the same connection + ASSERT_TRUE(db1.AcquireAdvisoryLock("mylock")); + // lock counter = 2 if MySQL >= 5.7, or 1 if MySQL < 5.7 (because + // acquiring a lock releases all the previously-acquired locks) + + ASSERT_TRUE(db1.ReleaseAdvisoryLock("mylock")); + // lock counter = 1 if MySQL >= 5.7, or 0 if MySQL < 5.7 + + // Try and release twice the lock + db1.ReleaseAdvisoryLock("mylock"); // Succeeds iff MySQL >= 5.7 + + ASSERT_TRUE(db1.AcquireAdvisoryLock("mylock2")); // lock counter = 1 + + { + OrthancDatabases::MySQLDatabase db2(globalParameters_); + db2.Open(); + + // The "db1" is still actively locking + ASSERT_FALSE(db2.AcquireAdvisoryLock("mylock2")); + + // Release the "db1" lock + ASSERT_TRUE(db1.ReleaseAdvisoryLock("mylock2")); + ASSERT_FALSE(db1.ReleaseAdvisoryLock("mylock2")); + + // "db2" can now acquire the lock, but not "db1" + ASSERT_TRUE(db2.AcquireAdvisoryLock("mylock2")); + ASSERT_FALSE(db1.AcquireAdvisoryLock("mylock2")); + } + + // "db2" is closed, "db1" can now acquire the lock + ASSERT_TRUE(db1.AcquireAdvisoryLock("mylock2")); +} + + + +/** + * WARNING: The following test only succeeds if MySQL >= 5.7. This is + * because in MySQL < 5.7, acquiring a lock by calling "SELECT + * GET_LOCK()" releases all the previously acquired locks! + **/ +TEST(MySQL, DISABLED_Lock3) +{ + OrthancDatabases::MySQLDatabase::ClearDatabase(globalParameters_); + + OrthancDatabases::MySQLDatabase db1(globalParameters_); + db1.Open(); + + ASSERT_TRUE(db1.AcquireAdvisoryLock("mylock1")); // lock counter = 1 + ASSERT_TRUE(db1.AcquireAdvisoryLock("mylock2")); // lock counter = 1 + + { + OrthancDatabases::MySQLDatabase db2(globalParameters_); + db2.Open(); + + ASSERT_FALSE(db2.AcquireAdvisoryLock("mylock1")); + } +} + + static int64_t CountFiles(OrthancDatabases::MySQLDatabase& db) { OrthancDatabases::Query query("SELECT COUNT(*) FROM StorageArea", true); OrthancDatabases::MySQLStatement s(db, query); OrthancDatabases::MySQLTransaction t(db); OrthancDatabases::Dictionary d; - std::auto_ptr result(s.Execute(t, d)); + std::unique_ptr result(s.Execute(t, d)); return dynamic_cast(result->GetField(0)).GetValue(); } @@ -146,15 +216,15 @@ } { - std::auto_ptr t(db.CreateTransaction(false)); + std::unique_ptr t(db.CreateTransaction(false)); ASSERT_FALSE(t->IsImplicit()); } { OrthancDatabases::Query query("CREATE TABLE test(id INT)", false); - std::auto_ptr s(db.Compile(query)); + std::unique_ptr s(db.Compile(query)); - std::auto_ptr t(db.CreateTransaction(true)); + std::unique_ptr t(db.CreateTransaction(true)); ASSERT_TRUE(t->IsImplicit()); ASSERT_THROW(t->Commit(), Orthanc::OrthancException); ASSERT_THROW(t->Rollback(), Orthanc::OrthancException); @@ -170,9 +240,9 @@ { // An implicit transaction does not need to be explicitely committed OrthancDatabases::Query query("CREATE TABLE test2(id INT)", false); - std::auto_ptr s(db.Compile(query)); + std::unique_ptr s(db.Compile(query)); - std::auto_ptr t(db.CreateTransaction(true)); + std::unique_ptr t(db.CreateTransaction(true)); OrthancDatabases::Dictionary args; t->ExecuteWithoutResult(*s, args); diff -Nru orthanc-mysql-2.0/Resources/CMake/DatabasesFrameworkConfiguration.cmake orthanc-mysql-3.0/Resources/CMake/DatabasesFrameworkConfiguration.cmake --- orthanc-mysql-2.0/Resources/CMake/DatabasesFrameworkConfiguration.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/CMake/DatabasesFrameworkConfiguration.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,7 +1,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License @@ -28,7 +28,6 @@ if (ENABLE_POSTGRESQL_BACKEND) set(ENABLE_CRYPTO_OPTIONS ON) - set(ENABLE_SSL ON) set(ENABLE_ZLIB ON) if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") @@ -53,14 +52,30 @@ ## Configure the Orthanc Framework ##################################################################### -# Those modules of the Orthanc framework are not needed when dealing -# with databases -set(ENABLE_MODULE_IMAGES OFF) -set(ENABLE_MODULE_JOBS OFF) -set(ENABLE_MODULE_DICOM OFF) +include_directories(${ORTHANC_FRAMEWORK_ROOT}) + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "system") + link_libraries(${ORTHANC_FRAMEWORK_LIBRARIES}) + + if (ENABLE_SQLITE_BACKEND) + add_definitions(-DORTHANC_ENABLE_SQLITE=1) + endif() + + set(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test") + set(USE_GOOGLE_TEST_DEBIAN_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)") + mark_as_advanced(USE_GOOGLE_TEST_DEBIAN_PACKAGE) + include(${CMAKE_SOURCE_DIR}/../Resources/Orthanc/CMake/GoogleTestConfiguration.cmake) + +else() + # Those modules of the Orthanc framework are not needed when dealing + # with databases + set(ENABLE_MODULE_IMAGES OFF) + set(ENABLE_MODULE_JOBS OFF) + set(ENABLE_MODULE_DICOM OFF) + + include(${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/OrthancFrameworkConfiguration.cmake) +endif() -include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkConfiguration.cmake) -include_directories(${ORTHANC_ROOT}) ##################################################################### diff -Nru orthanc-mysql-2.0/Resources/CMake/DatabasesFrameworkParameters.cmake orthanc-mysql-3.0/Resources/CMake/DatabasesFrameworkParameters.cmake --- orthanc-mysql-2.0/Resources/CMake/DatabasesFrameworkParameters.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/CMake/DatabasesFrameworkParameters.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,7 +1,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License @@ -22,8 +22,11 @@ ## Import the parameters of the Orthanc Framework ##################################################################### -include(${CMAKE_CURRENT_LIST_DIR}/../../Resources/Orthanc/DownloadOrthancFramework.cmake) -include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkParameters.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/../Orthanc/CMake/DownloadOrthancFramework.cmake) + +if (NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "system") + include(${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/OrthancFrameworkParameters.cmake) +endif() ##################################################################### diff -Nru orthanc-mysql-2.0/Resources/CMake/DatabasesPluginConfiguration.cmake orthanc-mysql-3.0/Resources/CMake/DatabasesPluginConfiguration.cmake --- orthanc-mysql-2.0/Resources/CMake/DatabasesPluginConfiguration.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/CMake/DatabasesPluginConfiguration.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,7 +1,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License @@ -19,7 +19,8 @@ include(${CMAKE_SOURCE_DIR}/../Resources/CMake/DatabasesFrameworkConfiguration.cmake) -include(${ORTHANC_ROOT}/Resources/CMake/AutoGeneratedCode.cmake) +include(${CMAKE_SOURCE_DIR}/../Resources/Orthanc/CMake/AutoGeneratedCode.cmake) +include(${CMAKE_SOURCE_DIR}/../Resources/Orthanc/Plugins/OrthancPluginsExports.cmake) if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK) @@ -29,8 +30,8 @@ include_directories(${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Sdk-1.4.0) elseif (ORTHANC_SDK_VERSION STREQUAL "1.5.2") include_directories(${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Sdk-1.5.2) - elseif (ORTHANC_SDK_VERSION STREQUAL "framework") - include_directories(${ORTHANC_ROOT}/Plugins/Include) + elseif (ORTHANC_SDK_VERSION STREQUAL "1.5.4") + include_directories(${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Sdk-1.5.4) else() message(FATAL_ERROR "Unsupported version of the Orthanc plugin SDK: ${ORTHANC_SDK_VERSION}") endif() @@ -42,9 +43,26 @@ endif() +if (NOT DEFINED ORTHANC_OPTIMAL_VERSION_MAJOR) + message(FATAL_ERROR "ORTHANC_OPTIMAL_VERSION_MAJOR is not defined") +endif() + +if (NOT DEFINED ORTHANC_OPTIMAL_VERSION_MINOR) + message(FATAL_ERROR "ORTHANC_OPTIMAL_VERSION_MINOR is not defined") +endif() + +if (NOT DEFINED ORTHANC_OPTIMAL_VERSION_REVISION) + message(FATAL_ERROR "ORTHANC_OPTIMAL_VERSION_REVISION is not defined") +endif() + + add_definitions( -DHAS_ORTHANC_EXCEPTION=1 + -DORTHANC_BUILDING_SERVER_LIBRARY=0 -DORTHANC_ENABLE_PLUGINS=1 + -DORTHANC_OPTIMAL_VERSION_MAJOR=${ORTHANC_OPTIMAL_VERSION_MAJOR} + -DORTHANC_OPTIMAL_VERSION_MINOR=${ORTHANC_OPTIMAL_VERSION_MINOR} + -DORTHANC_OPTIMAL_VERSION_REVISION=${ORTHANC_OPTIMAL_VERSION_REVISION} ) @@ -53,9 +71,7 @@ ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/GlobalProperties.cpp ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/IndexBackend.cpp ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/StorageBackend.cpp - ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp - - # New from "db-changes" - ${ORTHANC_ROOT}/OrthancServer/Search/DatabaseConstraint.cpp - ${ORTHANC_ROOT}/OrthancServer/Search/ISqlLookupFormatter.cpp + ${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Databases/DatabaseConstraint.cpp + ${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Databases/ISqlLookupFormatter.cpp + ${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp ) diff -Nru orthanc-mysql-2.0/Resources/CMake/DatabasesPluginParameters.cmake orthanc-mysql-3.0/Resources/CMake/DatabasesPluginParameters.cmake --- orthanc-mysql-2.0/Resources/CMake/DatabasesPluginParameters.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/CMake/DatabasesPluginParameters.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,7 +1,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License @@ -25,9 +25,8 @@ # Advanced parameters to fine-tune linking against system libraries set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK") -set(ORTHANC_SDK_VERSION "1.5.2" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"0.9.5\", \"1.4.0\", \"1.5.2\" or \"framework\")") +set(ORTHANC_SDK_VERSION "1.5.4" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"0.9.5\", \"1.4.0\", \"1.5.2\", or \"1.5.4\")") include(${CMAKE_CURRENT_LIST_DIR}/DatabasesFrameworkParameters.cmake) set(ENABLE_GOOGLE_TEST ON) -set(HAS_EMBEDDED_RESOURCES ON) diff -Nru orthanc-mysql-2.0/Resources/CMake/MariaDBConfiguration.cmake orthanc-mysql-3.0/Resources/CMake/MariaDBConfiguration.cmake --- orthanc-mysql-2.0/Resources/CMake/MariaDBConfiguration.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/CMake/MariaDBConfiguration.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,7 +1,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License @@ -19,11 +19,11 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_MYSQL_CLIENT) set(MARIADB_CLIENT_VERSION_MAJOR "10") - set(MARIADB_CLIENT_VERSION_MINOR "3") - set(MARIADB_CLIENT_VERSION_PATCH "6") - set(MARIADB_PACKAGE_VERSION "3.0.5") + set(MARIADB_CLIENT_VERSION_MINOR "5") + set(MARIADB_CLIENT_VERSION_PATCH "5") + set(MARIADB_PACKAGE_VERSION "3.1.11") set(MARIADB_CLIENT_SOURCES_DIR ${CMAKE_BINARY_DIR}/mariadb-connector-c-${MARIADB_PACKAGE_VERSION}-src) - set(MARIADB_CLIENT_MD5 "b846584b8b7a39c51a6e83986b57c71c") + set(MARIADB_CLIENT_MD5 "cf9da5f0ac9ec72dd8309bdc1d1c6c2f") set(MARIADB_CLIENT_URL "http://orthanc.osimis.io/ThirdPartyDownloads/mariadb-connector-c-${MARIADB_PACKAGE_VERSION}-src.tar.gz") if (IS_DIRECTORY "${MARIADB_CLIENT_SOURCES_DIR}") @@ -37,7 +37,7 @@ if (FirstRun) execute_process( COMMAND ${PATCH_EXECUTABLE} -p0 -N -i - ${CMAKE_CURRENT_LIST_DIR}/../MariaDB/mariadb-connector-c-3.0.5.patch + ${CMAKE_CURRENT_LIST_DIR}/../MariaDB/mariadb-connector-c-${MARIADB_PACKAGE_VERSION}.patch WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE Failure ) @@ -52,17 +52,20 @@ include(${MARIADB_CLIENT_SOURCES_DIR}/cmake/CheckFunctions.cmake) include(${MARIADB_CLIENT_SOURCES_DIR}/cmake/CheckTypes.cmake) - set(MARIADB_CLIENT_VERSION "${MARIADB_CLIENT_VERSION_MAJOR}.${MARIADB_CLIENT_VERSION_MINOR}.${MARIADB_CLIENT_VERSION_PATCH}") + set(MARIADB_CLIENT_VERSION "${MARIADB_CLIENT_VERSION_MAJOR}.${MARIADB_CLIENT_VERSION_MINOR}") set(MARIADB_BASE_VERSION "mariadb-${MARIADB_CLIENT_VERSION_MAJOR}.${MARIADB_CLIENT_VERSION_MINOR}") math(EXPR MARIADB_VERSION_ID "${MARIADB_CLIENT_VERSION_MAJOR} * 10000 + ${MARIADB_CLIENT_VERSION_MINOR} * 100 + ${MARIADB_CLIENT_VERSION_PATCH}") - - set(HAVE_DLOPEN 1) + + add_definitions(-DHAVE_DLOPEN=1) + #set(HAVE_DLOPEN 1) # Replaced by the C macro above in 3.1.11 + set(PROTOCOL_VERSION ${MARIADB_CLIENT_VERSION_MAJOR}) set(MARIADB_PORT 3306) set(MARIADB_UNIX_ADDR "/var/run/mysqld/mysqld.sock") set(DEFAULT_CHARSET "latin1") + set(ENABLED_LOCAL_INFILE "AUTO") FOREACH(plugin mysql_native_password mysql_old_password pvio_socket) set(EXTERNAL_PLUGINS "${EXTERNAL_PLUGINS} extern struct st_mysql_client_plugin ${plugin}_client_plugin;\n") @@ -130,6 +133,21 @@ if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") link_libraries(shlwapi) + + # MariaDB connector requires the fibers API (file "fibersapi.h", + # e.g. function "IsThreadAFiber()"), that was introduced in + # Windows Vista. This is done by redefining the "_WIN32_WINNT" + # macro that is initially set to 0x501 (Windows XP) in + # "OrthancFramework/Resources/CMake/Compiler.cmake". + # https://docs.microsoft.com/en-us/windows/win32/api/fibersapi/nf-fibersapi-isthreadafiber + remove_definitions( + -DWINVER=0x0501 + -D_WIN32_WINNT=0x0501 + ) + add_definitions( + -DWINVER=0x0600 + -D_WIN32_WINNT=0x0600 + ) endif() else() @@ -148,10 +166,20 @@ message(FATAL_ERROR "Please install the libmysqlclient-dev package") endif() - check_library_exists(mysqlclient mysql_init "" HAVE_MYSQL_CLIENT_LIB) - if (NOT HAVE_MYSQL_CLIENT_LIB) - message(FATAL_ERROR "Unable to find the mysqlclient library") - endif() - - link_libraries(mysqlclient) + find_library(MYSQL_CLIENT_LIB NAMES mysqlclient PATHS + /usr/lib/mysql + /usr/local/lib/mysql + ) + + if (MYSQL_CLIENT_LIB) + check_library_exists(${MYSQL_CLIENT_LIB} mysql_init "" HAVE_MYSQL_CLIENT_LIB) + if (NOT HAVE_MYSQL_CLIENT_LIB) + message(FATAL_ERROR "Unable to use mysql_init from mysqlclient library") + endif() + get_filename_component(MYSQL_CLIENT_LIB_PATH ${MYSQL_CLIENT_LIB} DIRECTORY) + link_directories(${MYSQL_CLIENT_LIB_PATH}) + link_libraries(mysqlclient) + else() + message(FATAL_ERROR "Unable to find the mysqlclient library") + endif() endif() diff -Nru orthanc-mysql-2.0/Resources/CMake/PostgreSQLConfiguration.cmake orthanc-mysql-3.0/Resources/CMake/PostgreSQLConfiguration.cmake --- orthanc-mysql-2.0/Resources/CMake/PostgreSQLConfiguration.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/CMake/PostgreSQLConfiguration.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,7 +1,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU Affero General Public License @@ -21,23 +21,38 @@ ## PostgreSQL ##################################################################### -INCLUDE(CheckTypeSize) INCLUDE(CheckCSourceCompiles) INCLUDE(CheckFunctionExists) +INCLUDE(CheckIncludeFiles) INCLUDE(CheckStructHasMember) +INCLUDE(CheckTypeSize) + + +macro(PrepareCMakeConfigurationFile Source Target) + execute_process( + COMMAND + ${PYTHON_EXECUTABLE} + "${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/PrepareCMakeConfigurationFile.py" "${Source}" "${Target}" + ERROR_VARIABLE tmp + OUTPUT_VARIABLE out + ) + + if (tmp) + message(FATAL_ERROR "Cannot find ${Source}") + endif() +endmacro() if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPQ) add_definitions(-DORTHANC_POSTGRESQL_STATIC=1) - SET(LIBPQ_MAJOR 9) - SET(LIBPQ_MINOR 6) - SET(LIBPQ_REVISION 1) - SET(LIBPQ_VERSION ${LIBPQ_MAJOR}.${LIBPQ_MINOR}.${LIBPQ_REVISION}) + SET(LIBPQ_MAJOR 13) + SET(LIBPQ_MINOR 1) + SET(LIBPQ_VERSION ${LIBPQ_MAJOR}.${LIBPQ_MINOR}) SET(LIBPQ_SOURCES_DIR ${CMAKE_BINARY_DIR}/postgresql-${LIBPQ_VERSION}) DownloadPackage( - "eaa7e267e89ea1ed2693d2b88d3cd290" + "551302a823a1ab48b4ed14166beebba9" "http://orthanc.osimis.io/ThirdPartyDownloads/postgresql-${LIBPQ_VERSION}.tar.gz" "${LIBPQ_SOURCES_DIR}") @@ -47,20 +62,36 @@ ## if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - add_definitions( - -DEXEC_BACKEND - ) + if (EXISTS ${AUTOGENERATED_DIR}/pg_config_os.h) + set(FirstRun OFF) + else() + set(FirstRun ON) + endif() configure_file( ${LIBPQ_SOURCES_DIR}/src/include/port/win32.h ${AUTOGENERATED_DIR}/pg_config_os.h COPYONLY) + if (FirstRun) + # This is needed on MSVC2008 to have an implementation of "isinf()" and "isnan()" + file(APPEND ${AUTOGENERATED_DIR}/pg_config_os.h " +#if defined(_MSC_VER) +# include +# include +# if !defined(isinf) +# define isinf(d) ((_fpclass(d) == _FPCLASS_PINF) ? 1 : ((_fpclass(d) == _FPCLASS_NINF) ? -1 : 0)) +# endif +# if !defined(isnan) +# define isnan(d) (_isnan(d)) +# endif +#endif +") + endif() + elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") add_definitions( -D_GNU_SOURCE - -D_THREAD_SAFE - -D_POSIX_PTHREAD_SEMANTICS ) configure_file( @@ -101,165 +132,194 @@ ## Generation of "pg_config.h" ## - if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - configure_file( - ${LIBPQ_SOURCES_DIR}/src/include/pg_config_ext.h.win32 - ${AUTOGENERATED_DIR}/pg_config_ext.h - COPYONLY) + set(PG_VERSION "\"${LIBPQ_MAJOR}.${LIBPQ_MINOR}\"") + math(EXPR PG_VERSION_NUM "${LIBPQ_MAJOR} * 10000 + ${LIBPQ_MINOR}") - configure_file( - ${LIBPQ_SOURCES_DIR}/src/include/pg_config.h.win32 - ${AUTOGENERATED_DIR}/pg_config.h - COPYONLY) + include(${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/func_accept_args.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/CheckTypeAlignment.cmake) - if (CMAKE_COMPILER_IS_GNUCXX) # MinGW - add_definitions( - -DPG_PRINTF_ATTRIBUTE=gnu_printf - -DHAVE_GETTIMEOFDAY - -DHAVE_LONG_LONG_INT_64 - -DHAVE_STRUCT_ADDRINFO - -DHAVE_STRUCT_SOCKADDR_STORAGE - -DHAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY - ) - endif() - - if (ENABLE_SSL) - add_definitions( - -DHAVE_LIBSSL=1 - -DUSE_OPENSSL=1 - ) - endif() + check_include_file("execinfo.h" HAVE_EXECINFO_H) + check_include_file("getopt.h" HAVE_GETOPT_H) + check_include_file("ifaddrs.h" HAVE_IFADDRS_H) + check_include_file("inttypes.h" HAVE_INTTYPES_H) + check_include_file("langinfo.h" HAVE_LANGINFO_H) + check_include_file("memory.h" HAVE_MEMORY_H) + check_include_file("netinet/tcp.h" HAVE_NETINET_TCP_H) + check_include_file("readline/history.h" HAVE_READLINE_HISTORY_H) + check_include_file("readline/readline.h" HAVE_READLINE_READLINE_H) + check_include_file("stdbool.h" HAVE_STDBOOL_H) + check_include_file("stdlib.h" HAVE_STDLIB_H) + check_include_file("string.h" HAVE_STRING_H) + check_include_file("strings.h" HAVE_STRINGS_H) + check_include_file("sys/epoll.h" HAVE_SYS_EPOLL_H) + check_include_file("sys/event.h" HAVE_SYS_EVENT_H) + check_include_file("sys/ipc.h" HAVE_SYS_IPC_H) + check_include_file("sys/prctl.h" HAVE_SYS_PRCTL_H) + check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H) + check_include_file("sys/select.h" HAVE_SYS_SELECT_H) + check_include_file("sys/sem.h" HAVE_SYS_SEM_H) + check_include_file("sys/shm.h" HAVE_SYS_SHM_H) + check_include_file("sys/stat.h" HAVE_SYS_STAT_H) + check_include_file("sys/termios.h" HAVE_SYS_TERMIOS_H) + check_include_file("sys/types.h" HAVE_SYS_TYPES_H) + check_include_file("sys/un.h" HAVE_SYS_UN_H) + check_include_file("termios.h" HAVE_TERMIOS_H) + check_include_file("unistd.h" HAVE_UNISTD_H) + check_include_file("wctype.h" HAVE_WCTYPE_H) + + check_type_size("long long int" SIZEOF_LONG_LONG_INT) + if (SIZEOF_LONG_LONG_INT EQUAL 8) + set(HAVE_LONG_LONG_INT_64 1) + set(PG_INT64_TYPE "long long int") + endif() - elseif(CROSS_COMPILING) - message(FATAL_ERROR "Cannot auto-generate the configuration file cross-compiling") - + check_type_size("long int" SIZEOF_LONG_INT) + if (SIZEOF_LONG_INT EQUAL 8) + set(HAVE_LONG_INT_64 1) + set(PG_INT64_TYPE "long int") + endif() + + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(ALIGNOF_DOUBLE 8) + set(ALIGNOF_INT 4) + set(ALIGNOF_LONG 4) + set(ALIGNOF_LONG_LONG_INT 8) + set(ALIGNOF_SHORT 2) else() - configure_file( - ${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/pg_config_ext.h - ${AUTOGENERATED_DIR}/pg_config_ext.h - COPYONLY - ) - - set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h;netdb.h;sys/types.h") - - include(${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/func_accept_args.cmake) - set(ACCEPT_TYPE_ARG3 ${ACCEPT_TYPE_ARG3}) - - check_type_size("long int" SIZE_LONG_INT) - if (SIZE_LONG_INT EQUAL 8) - set(HAVE_LONG_INT_64 1) - endif() - - check_type_size("long long int" SIZE_LONG_LONG_INT) - if (SIZE_LONG_LONG_INT EQUAL 8) - set(HAVE_LONG_LONG_INT_64 1) - endif() - - file(READ ${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/c_flexmember.c SOURCE) - check_c_source_compiles("${SOURCE}" c_flexmember) - if (c_flexmember) - set(FLEXIBLE_ARRAY_MEMBER "/**/") - endif() - - if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR - CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") - set(PG_PRINTF_ATTRIBUTE "printf") - else() - file(READ ${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/printf_archetype.c SOURCE) - check_c_source_compiles("${SOURCE}" printf_archetype) - if (printf_archetype) - set(PG_PRINTF_ATTRIBUTE "gnu_printf") - else() - set(PG_PRINTF_ATTRIBUTE "printf") - endif() - endif() - - check_function_exists("isinf" HAVE_ISINF) - check_function_exists("getaddrinfo" HAVE_GETADDRINFO) - check_function_exists("gettimeofday" HAVE_GETTIMEOFDAY) - check_function_exists("snprintf" HAVE_DECL_SNPRINTF) - check_function_exists("srandom" HAVE_SRANDOM) - check_function_exists("strlcat" HAVE_DECL_STRLCAT) - check_function_exists("strlcpy" HAVE_DECL_STRLCPY) - check_function_exists("unsetenv" HAVE_UNSETENV) - check_function_exists("vsnprintf" HAVE_DECL_VSNPRINTF) - - check_type_size("struct addrinfo" SIZE_STRUCT_ADDRINFO) - if (HAVE_SIZE_STRUCT_ADDRINFO) - set(HAVE_STRUCT_ADDRINFO 1) - endif() - - check_type_size("struct sockaddr_storage" SIZE_STRUCT_SOCKADDR_STORAGE) - if (HAVE_SIZE_STRUCT_SOCKADDR_STORAGE) - set(HAVE_STRUCT_SOCKADDR_STORAGE 1) - endif() - - set(MEMSET_LOOP_LIMIT 1024) # This is hardcoded in "postgresql-9.6.1/configure" - set(DEF_PGPORT 5432) # Default port number of PostgreSQL - set(DEF_PGPORT_STR "\"5432\"") # Same as above, as a string - set(PG_VERSION "\"${LIBPQ_VERSION}\"") # Version of PostgreSQL, as a string - - # Version of PostgreSQL, as a number - math(EXPR PG_VERSION_NUM "${LIBPQ_MAJOR} * 10000 + ${LIBPQ_MINOR} * 100 + ${LIBPQ_REVISION}") - - set(HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1) # TODO Autodetection - - # Compute maximum alignment of any basic type. - # We assume long's alignment is at least as strong as char, short, or int; - # but we must check long long (if it exists) and double. - check_type_size("long" SIZE_LONG) - check_type_size("long long" SIZE_LONG_LONG) - check_type_size("double" SIZE_DOUBLE) - set(MAXIMUM_ALIGNOF ${SIZE_LONG}) - if(SIZE_LONG_LONG AND SIZE_LONG_LONG GREATER MAXIMUM_ALIGNOF) - set(MAXIMUM_ALIGNOF ${SIZE_LONG_LONG}) - endif() - if(SIZE_DOUBLE GREATER MAXIMUM_ALIGNOF) - set(MAXIMUM_ALIGNOF ${SIZE_DOUBLE}) - endif() - - check_include_file("poll.h" HAVE_POLL_H) - check_include_file("net/if.h" HAVE_NET_IF_H) - check_include_file("netinet/in.h" HAVE_NETINET_IN_H) - check_include_file("netinet/tcp.h" HAVE_NETINET_TCP_H) - check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) - check_include_file("sys/un.h" HAVE_SYS_UN_H) - - If (NOT HAVE_NET_IF_H) # This is the case of OpenBSD - unset(HAVE_NET_IF_H CACHE) - check_include_files("sys/socket.h;net/if.h" HAVE_NET_IF_H) - endif() - - if (NOT HAVE_NETINET_TCP_H) # This is the case of OpenBSD - unset(HAVE_NETINET_TCP_H CACHE) - check_include_files("sys/socket.h;netinet/tcp.h" HAVE_NETINET_TCP_H) - endif() - - if (ENABLE_SSL) - set(HAVE_LIBSSL 1) - set(HAVE_SSL_GET_CURRENT_COMPRESSION 1) - set(USE_OPENSSL 1) - endif() + check_type_alignment(double ALIGNOF_DOUBLE) + check_type_alignment(int ALIGNOF_INT) + check_type_alignment(long ALIGNOF_LONG) + check_type_alignment("long long int" ALIGNOF_LONG_LONG_INT) + check_type_alignment(short ALIGNOF_SHORT) + endif() + + set(MAXIMUM_ALIGNOF ${ALIGNOF_LONG}) + if (MAXIMUM_ALIGNOF LESS ALIGNOF_DOUBLE) + set(MAXIMUM_ALIGNOF ${ALIGNOF_DOUBLE}) + endif() + if (HAVE_LONG_LONG_INT_64 AND (MAXIMUM_ALIGNOF LESS HAVE_LONG_LONG_INT_64)) + set(MAXIMUM_ALIGNOF ${HAVE_LONG_LONG_INT_64}) + endif() + + if (CMAKE_COMPILER_IS_GNUCXX OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(PG_PRINTF_ATTRIBUTE "gnu_printf") + set(pg_restrict "__restrict") + set(restrict "__restrict") + else() + # The empty string below wouldn't work (it would do an #undef) + set(pg_restrict " ") + set(restrict " ") + endif() - execute_process( - COMMAND - ${PYTHON_EXECUTABLE} - "${CMAKE_CURRENT_LIST_DIR}/../PostgreSQL/PrepareCMakeConfigurationFile.py" - "${LIBPQ_SOURCES_DIR}/src/include/pg_config.h.in" - "${AUTOGENERATED_DIR}/pg_config.h.in" - ERROR_VARIABLE NO_PG_CONFIG - OUTPUT_VARIABLE out - ) + if (MSVC) + set(inline "__inline") + endif() + + if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h;winsock2.h;ws2tcpip.h;float.h;math.h") + else() + set(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h;sys/socket.h;netdb.h;float.h;math.h") + endif() - if (NO_PG_CONFIG) - message(FATAL_ERROR "Cannot find pg_config.h.in") - endif() - - configure_file( - ${AUTOGENERATED_DIR}/pg_config.h.in - ${AUTOGENERATED_DIR}/pg_config.h) + check_type_size("size_t" SIZEOF_SIZE_T) + check_type_size("struct addrinfo" HAVE_STRUCT_ADDRINFO) + check_type_size("struct sockaddr_storage" HAVE_STRUCT_SOCKADDR_STORAGE) + check_struct_has_member("struct sockaddr_storage" ss_family + "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY) + + check_function_exists(gethostbyname_r HAVE_GETHOSTBYNAME_R) + check_function_exists(getopt HAVE_GETOPT) + check_function_exists(getopt_long HAVE_GETOPT_LONG) + check_function_exists(getpwuid_r HAVE_GETPWUID_R) + check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) + check_function_exists(random HAVE_RANDOM) + check_function_exists(srandom HAVE_SRANDOM) + check_function_exists(strchrnul HAVE_STRCHRNUL) + check_function_exists(strerror HAVE_STRERROR) + check_function_exists(strerror_r HAVE_STRERROR_R) + check_function_exists(unsetenv HAVE_UNSETENV) + check_function_exists(strlcat HAVE_STRLCAT) + check_function_exists(strlcpy HAVE_STRLCPY) + check_function_exists(getpeereid HAVE_GETPEEREID) + check_function_exists(getpeerucred HAVE_GETPEERUCRED) + check_function_exists(isinf HAVE_ISINF) + check_function_exists(isnan HAVE_ISNAN) + + check_symbol_exists(strlcpy "stdio.h;string.h" HAVE_DECL_STRLCPY) + if (NOT HAVE_DECL_STRLCPY) + set(HAVE_DECL_STRLCPY 0) endif() + check_symbol_exists(strlcat "stdio.h;string.h" HAVE_DECL_STRLCAT) + if (NOT HAVE_DECL_STRLCAT) + set(HAVE_DECL_STRLCAT 0) + endif() + check_symbol_exists(snprintf "stdio.h;string.h" HAVE_DECL_SNPRINTF) + if (NOT HAVE_DECL_SNPRINTF) + set(HAVE_DECL_SNPRINTF 0) + endif() + check_symbol_exists(vsnprintf "stdio.h;string.h" HAVE_DECL_VSNPRINTF) + if (NOT HAVE_DECL_VSNPRINTF) + set(HAVE_DECL_VSNPRINTF 0) + endif() + + check_c_source_compiles(" + #include + int main(void){ + struct timeval *tp; + struct timezone *tzp; + gettimeofday(tp,tzp); + return 0; + } + " GETTIMEOFDAY_2ARG) + + if(NOT GETTIMEOFDAY_2ARG) + set(GETTIMEOFDAY_1ARG 1) + endif(NOT GETTIMEOFDAY_2ARG) + + check_c_source_compiles(" + #include + int main(void){ + int res; + #ifndef __CYGWIN__ + res = timezone / 60; + #else + res = _timezone / 60; + #endif + return 0; + } + " HAVE_INT_TIMEZONE) + + # Hardcoded stuff from "./configure" of libpq + set(MEMSET_LOOP_LIMIT 1024) + set(BLCKSZ 8192) + set(XLOG_BLCKSZ 8192) + set(DEF_PGPORT 5432) + set(DEF_PGPORT_STR "\"${DEF_PGPORT}\"") + set(PG_KRB_SRVNAM "\"postgres\"") + + # Assume that zlib and openssl are always present + set(HAVE_LIBZ 1) + set(HAVE_LIBSSL 1) + set(HAVE_OPENSSL_INIT_SSL 1) + set(USE_OPENSSL 1) + set(USE_OPENSSL_RANDOM 1) + + PrepareCMakeConfigurationFile( + ${LIBPQ_SOURCES_DIR}/src/include/pg_config_ext.h.in + ${AUTOGENERATED_DIR}/pg_config_ext.h.in) + + PrepareCMakeConfigurationFile( + ${LIBPQ_SOURCES_DIR}/src/include/pg_config.h.in + ${AUTOGENERATED_DIR}/pg_config.h.in) + + configure_file( + ${AUTOGENERATED_DIR}/pg_config_ext.h.in + ${AUTOGENERATED_DIR}/pg_config_ext.h) + + configure_file( + ${AUTOGENERATED_DIR}/pg_config.h.in + ${AUTOGENERATED_DIR}/pg_config.h) @@ -272,20 +332,37 @@ "") add_definitions( - -D_REENTRANT -DFRONTEND - -DUNSAFE_STAT_OK -DSYSCONFDIR="" + -DTCP_NODELAY # For performance + + # Must be set for OpenSSL 1.1, not for OpenSSL 1.0?? + -DHAVE_BIO_GET_DATA=1 + -DHAVE_BIO_METH_NEW=1 ) include_directories( + ${LIBPQ_SOURCES_DIR}/src/backend ${LIBPQ_SOURCES_DIR}/src/include ${LIBPQ_SOURCES_DIR}/src/include/libpq ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq ) set(LIBPQ_SOURCES - ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-auth.c + # Don't use files from the "src/backend/" folder + ${LIBPQ_SOURCES_DIR}/src/common/base64.c + ${LIBPQ_SOURCES_DIR}/src/common/encnames.c + ${LIBPQ_SOURCES_DIR}/src/common/ip.c + ${LIBPQ_SOURCES_DIR}/src/common/link-canary.c + ${LIBPQ_SOURCES_DIR}/src/common/md5.c + ${LIBPQ_SOURCES_DIR}/src/common/saslprep.c + ${LIBPQ_SOURCES_DIR}/src/common/scram-common.c + ${LIBPQ_SOURCES_DIR}/src/common/sha2_openssl.c + ${LIBPQ_SOURCES_DIR}/src/common/string.c + ${LIBPQ_SOURCES_DIR}/src/common/unicode_norm.c + ${LIBPQ_SOURCES_DIR}/src/common/wchar.c + ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-auth-scram.c + ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-auth.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-connect.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-exec.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-lobj.c @@ -293,37 +370,37 @@ ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-print.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-protocol2.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-protocol3.c + ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-secure-common.c + ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-secure-openssl.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-secure.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/libpq-events.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/pqexpbuffer.c - - # libpgport C files we always use ${LIBPQ_SOURCES_DIR}/src/port/chklocale.c + ${LIBPQ_SOURCES_DIR}/src/port/explicit_bzero.c + ${LIBPQ_SOURCES_DIR}/src/port/getaddrinfo.c ${LIBPQ_SOURCES_DIR}/src/port/inet_net_ntop.c ${LIBPQ_SOURCES_DIR}/src/port/noblock.c + ${LIBPQ_SOURCES_DIR}/src/port/pg_strong_random.c ${LIBPQ_SOURCES_DIR}/src/port/pgstrcasecmp.c ${LIBPQ_SOURCES_DIR}/src/port/pqsignal.c + ${LIBPQ_SOURCES_DIR}/src/port/snprintf.c + ${LIBPQ_SOURCES_DIR}/src/port/strerror.c ${LIBPQ_SOURCES_DIR}/src/port/thread.c - - ${LIBPQ_SOURCES_DIR}/src/backend/libpq/ip.c - ${LIBPQ_SOURCES_DIR}/src/backend/libpq/md5.c - ${LIBPQ_SOURCES_DIR}/src/backend/utils/mb/encnames.c - ${LIBPQ_SOURCES_DIR}/src/backend/utils/mb/wchar.c ) - if (ENABLE_SSL) - list(APPEND LIBPQ_SOURCES - ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/fe-secure-openssl.c + if (NOT HAVE_STRLCPY) + LIST(APPEND LIBPQ_SOURCES + ${LIBPQ_SOURCES_DIR}/src/port/strlcpy.c # Doesn't work on OS X ) endif() - - if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + if (NOT HAVE_GETPEEREID) LIST(APPEND LIBPQ_SOURCES - ${LIBPQ_SOURCES_DIR}/src/port/strlcpy.c - ) + ${LIBPQ_SOURCES_DIR}/src/port/getpeereid.c # Doesn't work on OS X + ) + endif() - elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") + if (CMAKE_SYSTEM_NAME STREQUAL "Windows") link_libraries(secur32) include_directories( @@ -332,19 +409,16 @@ ) LIST(APPEND LIBPQ_SOURCES - # libpgport C files that are needed if identified by configure + ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/pthread-win32.c ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/win32.c - ${LIBPQ_SOURCES_DIR}/src/port/crypt.c + ${LIBPQ_SOURCES_DIR}/src/port/dirmod.c ${LIBPQ_SOURCES_DIR}/src/port/inet_aton.c ${LIBPQ_SOURCES_DIR}/src/port/open.c ${LIBPQ_SOURCES_DIR}/src/port/pgsleep.c - ${LIBPQ_SOURCES_DIR}/src/port/snprintf.c - ${LIBPQ_SOURCES_DIR}/src/port/system.c + ${LIBPQ_SOURCES_DIR}/src/port/system.c ${LIBPQ_SOURCES_DIR}/src/port/win32setlocale.c - ${LIBPQ_SOURCES_DIR}/src/port/getaddrinfo.c - ${LIBPQ_SOURCES_DIR}/src/port/strlcpy.c ) - + if (CMAKE_COMPILER_IS_GNUCXX OR (MSVC AND MSVC_VERSION GREATER 1800)) # Starting Visual Studio 2013 (version 1800), it is necessary to also add "win32error.c" @@ -352,32 +426,21 @@ endif() if (MSVC) - LIST(APPEND LIBPQ_SOURCES ${LIBPQ_SOURCES_DIR}/src/interfaces/libpq/pthread-win32.c) + include_directories( + ${LIBPQ_SOURCES_DIR}/src/include/port/win32_msvc + ) + + LIST(APPEND LIBPQ_SOURCES + ${LIBPQ_SOURCES_DIR}/src/port/dirent.c + ) endif() endif() - if (CMAKE_COMPILER_IS_GNUCXX AND - NOT CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") - LIST(APPEND LIBPQ_SOURCES - ${LIBPQ_SOURCES_DIR}/src/port/getpeereid.c - ) - - elseif (MSVC) - include_directories( - ${LIBPQ_SOURCES_DIR}/src/include/port/win32_msvc - ) - - LIST(APPEND LIBPQ_SOURCES - ${LIBPQ_SOURCES_DIR}/src/port/dirent.c - ${LIBPQ_SOURCES_DIR}/src/port/dirmod.c - ) - endif() - source_group(ThirdParty\\PostgreSQL REGULAR_EXPRESSION ${LIBPQ_SOURCES_DIR}/.*) else() set(PostgreSQL_ADDITIONAL_VERSIONS - "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") + "13" "12" "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") if (NOT WIN32) foreach (suffix ${PostgreSQL_ADDITIONAL_VERSIONS}) list(APPEND PostgreSQL_ADDITIONAL_SEARCH_PATHS diff -Nru orthanc-mysql-2.0/Resources/MariaDB/mariadb-connector-c-3.1.11.patch orthanc-mysql-3.0/Resources/MariaDB/mariadb-connector-c-3.1.11.patch --- orthanc-mysql-2.0/Resources/MariaDB/mariadb-connector-c-3.1.11.patch 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/MariaDB/mariadb-connector-c-3.1.11.patch 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,54 @@ +diff -urEb mariadb-connector-c-3.1.11-src.orig/include/ma_global.h mariadb-connector-c-3.1.11-src/include/ma_global.h +--- mariadb-connector-c-3.1.11-src.orig/include/ma_global.h 2020-12-16 13:47:31.950009259 +0100 ++++ mariadb-connector-c-3.1.11-src/include/ma_global.h 2020-12-16 13:50:23.705910282 +0100 +@@ -606,7 +606,9 @@ + #error "Neither int or long is of 4 bytes width" + #endif + +-#if !defined(HAVE_ULONG) && !defined(HAVE_LINUXTHREADS) && !defined(__USE_MISC) ++#if defined(__LSB_VERSION__) ++typedef unsigned long ulong; /* Short for unsigned long */ ++#elif !defined(HAVE_ULONG) && !defined(HAVE_LINUXTHREADS) && !defined(__USE_MISC) + typedef unsigned long ulong; /* Short for unsigned long */ + #endif + #ifndef longlong_defined +diff -urEb mariadb-connector-c-3.1.11-src.orig/include/mysql/client_plugin.h mariadb-connector-c-3.1.11-src/include/mysql/client_plugin.h +--- mariadb-connector-c-3.1.11-src.orig/include/mysql/client_plugin.h 2020-12-16 13:47:31.950009259 +0100 ++++ mariadb-connector-c-3.1.11-src/include/mysql/client_plugin.h 2020-12-16 13:50:37.913900837 +0100 +@@ -180,7 +180,7 @@ + @retval + a pointer to the loaded plugin, or NULL in case of a failure + */ +-struct st_mysql_client_plugin * ++struct st_mysql_client_plugin * STDCALL + mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, + int argc, ...); + +diff -urEb mariadb-connector-c-3.1.11-src.orig/include/mysql.h mariadb-connector-c-3.1.11-src/include/mysql.h +--- mariadb-connector-c-3.1.11-src.orig/include/mysql.h 2020-12-16 13:47:31.950009259 +0100 ++++ mariadb-connector-c-3.1.11-src/include/mysql.h 2020-12-16 13:54:01.145749406 +0100 +@@ -467,7 +467,7 @@ + MYSQL_CLIENT_PLUGIN_HEADER + }; + +-struct st_mysql_client_plugin * ++struct st_mysql_client_plugin * STDCALL + mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, + int argc, ...); + struct st_mysql_client_plugin * STDCALL +Only in mariadb-connector-c-3.1.11-src/include: mysql.h~ +diff -urEb mariadb-connector-c-3.1.11-src.orig/plugins/pvio/pvio_socket.c mariadb-connector-c-3.1.11-src/plugins/pvio/pvio_socket.c +--- mariadb-connector-c-3.1.11-src.orig/plugins/pvio/pvio_socket.c 2020-12-16 13:47:31.954009258 +0100 ++++ mariadb-connector-c-3.1.11-src/plugins/pvio/pvio_socket.c 2020-12-16 13:50:23.705910282 +0100 +@@ -60,6 +60,11 @@ + #define IS_SOCKET_EINTR(err) 0 + #endif + ++#if defined(__LSB_VERSION__) ++// WARNING: This definition might break true Linux Standard Base compatibility! ++# define MSG_DONTWAIT 0x40 /* Nonblocking IO. */ ++#endif ++ + #ifndef SOCKET_ERROR + #define SOCKET_ERROR -1 + #endif diff -Nru orthanc-mysql-2.0/Resources/Orthanc/CMake/AutoGeneratedCode.cmake orthanc-mysql-3.0/Resources/Orthanc/CMake/AutoGeneratedCode.cmake --- orthanc-mysql-2.0/Resources/Orthanc/CMake/AutoGeneratedCode.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/CMake/AutoGeneratedCode.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,78 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +set(EMBED_RESOURCES_PYTHON "${CMAKE_CURRENT_LIST_DIR}/../EmbedResources.py" + CACHE INTERNAL "Path to the EmbedResources.py script from Orthanc") +set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED") +set(AUTOGENERATED_SOURCES) + +file(MAKE_DIRECTORY ${AUTOGENERATED_DIR}) +include_directories(${AUTOGENERATED_DIR}) + +macro(EmbedResources) + # Convert a semicolon separated list to a whitespace separated string + set(SCRIPT_OPTIONS) + set(SCRIPT_ARGUMENTS) + set(DEPENDENCIES) + set(IS_PATH_NAME false) + + set(TARGET_BASE "${AUTOGENERATED_DIR}/EmbeddedResources") + + # Loop over the arguments of the function + foreach(arg ${ARGN}) + # Extract the first character of the argument + string(SUBSTRING "${arg}" 0 1 FIRST_CHAR) + if (${FIRST_CHAR} STREQUAL "-") + # If the argument starts with a dash "-", this is an option to + # EmbedResources.py + if (${arg} MATCHES "--target=.*") + # Does the argument starts with "--target="? + string(SUBSTRING "${arg}" 9 -1 TARGET) # 9 is the length of "--target=" + set(TARGET_BASE "${AUTOGENERATED_DIR}/${TARGET}") + else() + list(APPEND SCRIPT_OPTIONS ${arg}) + endif() + else() + if (${IS_PATH_NAME}) + list(APPEND SCRIPT_ARGUMENTS "${arg}") + list(APPEND DEPENDENCIES "${arg}") + set(IS_PATH_NAME false) + else() + list(APPEND SCRIPT_ARGUMENTS "${arg}") + set(IS_PATH_NAME true) + endif() + endif() + endforeach() + + add_custom_command( + OUTPUT + "${TARGET_BASE}.h" + "${TARGET_BASE}.cpp" + COMMAND ${PYTHON_EXECUTABLE} ${EMBED_RESOURCES_PYTHON} + ${SCRIPT_OPTIONS} "${TARGET_BASE}" ${SCRIPT_ARGUMENTS} + DEPENDS + ${EMBED_RESOURCES_PYTHON} + ${DEPENDENCIES} + ) + + list(APPEND AUTOGENERATED_SOURCES + "${TARGET_BASE}.cpp" + ) +endmacro() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/CMake/Compiler.cmake orthanc-mysql-3.0/Resources/Orthanc/CMake/Compiler.cmake --- orthanc-mysql-2.0/Resources/Orthanc/CMake/Compiler.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/CMake/Compiler.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,263 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +# This file sets all the compiler-related flags + + +# Save the current compiler flags to the cache every time cmake configures the project +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "compiler flags" FORCE) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" CACHE STRING "compiler flags" FORCE) + + +include(CheckLibraryExists) + +if ((CMAKE_CROSSCOMPILING AND NOT + "${CMAKE_SYSTEM_VERSION}" STREQUAL "CrossToolNg") OR + "${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + # Cross-compilation necessarily implies standalone and static build + SET(STATIC_BUILD ON) + SET(STANDALONE_BUILD ON) +endif() + + +if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + # Cache the environment variables "LSB_CC" and "LSB_CXX" for further + # use by "ExternalProject" in CMake + SET(CMAKE_LSB_CC $ENV{LSB_CC} CACHE STRING "") + SET(CMAKE_LSB_CXX $ENV{LSB_CXX} CACHE STRING "") +endif() + + +if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-long-long") + + # --std=c99 makes libcurl not to compile + # -pedantic gives a lot of warnings on OpenSSL + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -Wno-variadic-macros") + + if (CMAKE_CROSSCOMPILING) + # http://stackoverflow.com/a/3543845/881731 + set(CMAKE_RC_COMPILE_OBJECT " -O coff -I ") + endif() + +elseif (MSVC) + # Use static runtime under Visual Studio + # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace + # http://stackoverflow.com/a/6510446 + foreach(flag_var + CMAKE_C_FLAGS_DEBUG + CMAKE_CXX_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + string(REGEX REPLACE "/MDd" "/MTd" ${flag_var} "${${flag_var}}") + endforeach(flag_var) + + # Add /Zm256 compiler option to Visual Studio to fix PCH errors + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm256") + + # New in Orthanc 1.5.5 + if (MSVC_MULTIPLE_PROCESSES) + # "If you omit the processMax argument in the /MP option, the + # compiler obtains the number of effective processors from the + # operating system, and then creates one process per effective + # processor" + # https://blog.kitware.com/cmake-building-with-all-your-cores/ + # https://docs.microsoft.com/en-us/cpp/build/reference/mp-build-with-multiple-processes + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + endif() + + add_definitions( + -D_CRT_SECURE_NO_WARNINGS=1 + -D_CRT_SECURE_NO_DEPRECATE=1 + ) + + if (MSVC_VERSION LESS 1600) + # Starting with Visual Studio >= 2010 (i.e. macro _MSC_VER >= + # 1600), Microsoft ships a standard-compliant + # header. For earlier versions of Visual Studio, give access to a + # compatibility header. + # http://stackoverflow.com/a/70630/881731 + # https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h#External_links + include_directories(${CMAKE_CURRENT_LIST_DIR}/../../Resources/ThirdParty/VisualStudio) + endif() + + link_libraries(netapi32) +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + # In FreeBSD/OpenBSD, the "/usr/local/" folder contains the ports and need to be imported + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/local/include") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/local/include") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib") +endif() + + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD" AND + NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + # The "--no-undefined" linker flag makes the shared libraries + # (plugins ModalityWorklists and ServeFolders) fail to compile on + # OpenBSD, and make the PostgreSQL plugin complain about missing + # "environ" global variable in FreeBSD + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") + endif() + + # Remove the "-rdynamic" option + # http://www.mail-archive.com/cmake@cmake.org/msg08837.html + set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + link_libraries(pthread) + + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + link_libraries(rt) + endif() + + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND + NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + link_libraries(dl) + endif() + + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND + NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + # The "--as-needed" linker flag is not available on FreeBSD and OpenBSD + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") + endif() + + if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" AND + NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + # FreeBSD/OpenBSD have just one single interface for file + # handling, which is 64bit clean, so there is no need to define macro + # for LFS (Large File Support). + # https://ohse.de/uwe/articles/lfs.html + add_definitions( + -D_LARGEFILE64_SOURCE=1 + -D_FILE_OFFSET_BITS=64 + ) + endif() + +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + if (MSVC) + message("MSVC compiler version = " ${MSVC_VERSION} "\n") + # Starting Visual Studio 2013 (version 1800), it is not possible + # to target Windows XP anymore + if (MSVC_VERSION LESS 1800) + add_definitions( + -DWINVER=0x0501 + -D_WIN32_WINNT=0x0501 + ) + endif() + else() + add_definitions( + -DWINVER=0x0501 + -D_WIN32_WINNT=0x0501 + ) + endif() + + add_definitions( + -D_CRT_SECURE_NO_WARNINGS=1 + ) + link_libraries(rpcrt4 ws2_32) + + if (CMAKE_COMPILER_IS_GNUCXX) + # Some additional C/C++ compiler flags for MinGW + SET(MINGW_NO_WARNINGS "-Wno-unused-function -Wno-unused-variable") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MINGW_NO_WARNINGS} -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MINGW_NO_WARNINGS}") + + if (DYNAMIC_MINGW_STDLIB) + else() + # This is a patch for MinGW64 + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++") + endif() + + CHECK_LIBRARY_EXISTS(winpthread pthread_create "" HAVE_WIN_PTHREAD) + if (HAVE_WIN_PTHREAD) + if (DYNAMIC_MINGW_STDLIB) + else() + # This line is necessary to compile with recent versions of MinGW, + # otherwise "libwinpthread-1.dll" is not statically linked. + SET(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic") + endif() + add_definitions(-DHAVE_WIN_PTHREAD=1) + else() + add_definitions(-DHAVE_WIN_PTHREAD=0) + endif() + endif() + +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + add_definitions( + -D_XOPEN_SOURCE=1 + ) + link_libraries(iconv) + +elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + message("Building using Emscripten (for WebAssembly or asm.js targets)") + include(${CMAKE_CURRENT_LIST_DIR}/EmscriptenParameters.cmake) + +elseif (CMAKE_SYSTEM_NAME STREQUAL "Android") + +else() + message("Unknown target platform: ${CMAKE_SYSTEM_NAME}") + message(FATAL_ERROR "Support your platform here") +endif() + + +if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING) + if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pg") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg") + else() + message(FATAL_ERROR "Don't know how to enable profiling on your configuration") + endif() +endif() + + +if (CMAKE_COMPILER_IS_GNUCXX) + # "When creating a static library using binutils (ar) and there + # exist a duplicate object name (e.g. a/Foo.cpp.o, b/Foo.cpp.o), the + # resulting static library can end up having only one of the + # duplicate objects. [...] This bug only happens if there are many + # objects." The trick consists in replacing the "r" argument + # ("replace") provided to "ar" (as used in CMake < 3.1) by the "q" + # argument ("quick append"). This is because of the fact that CMake + # will invoke "ar" several times with several batches of ".o" + # objects, and using "r" would overwrite symbols defined in + # preceding batches. https://cmake.org/Bug/view.php?id=14874 + set(CMAKE_CXX_ARCHIVE_APPEND " q ") +endif() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake orthanc-mysql-3.0/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake --- orthanc-mysql-2.0/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,590 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + + +## +## Check whether the parent script sets the mandatory variables +## + +if (NOT DEFINED ORTHANC_FRAMEWORK_SOURCE OR + (NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "system" AND + NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" AND + NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "web" AND + NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" AND + NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "path")) + message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_SOURCE must be set to \"system\", \"hg\", \"web\", \"archive\" or \"path\"") +endif() + + +## +## Detection of the requested version +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" OR + ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR + ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") + if (NOT DEFINED ORTHANC_FRAMEWORK_VERSION) + message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_VERSION must be set") + endif() + + if (DEFINED ORTHANC_FRAMEWORK_MAJOR OR + DEFINED ORTHANC_FRAMEWORK_MINOR OR + DEFINED ORTHANC_FRAMEWORK_REVISION OR + DEFINED ORTHANC_FRAMEWORK_MD5) + message(FATAL_ERROR "Some internal variable has been set") + endif() + + set(ORTHANC_FRAMEWORK_MD5 "") + + if (NOT DEFINED ORTHANC_FRAMEWORK_BRANCH) + if (ORTHANC_FRAMEWORK_VERSION STREQUAL "mainline") + set(ORTHANC_FRAMEWORK_BRANCH "default") + set(ORTHANC_FRAMEWORK_MAJOR 999) + set(ORTHANC_FRAMEWORK_MINOR 999) + set(ORTHANC_FRAMEWORK_REVISION 999) + + else() + set(ORTHANC_FRAMEWORK_BRANCH "Orthanc-${ORTHANC_FRAMEWORK_VERSION}") + + set(RE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$") + string(REGEX REPLACE ${RE} "\\1" ORTHANC_FRAMEWORK_MAJOR ${ORTHANC_FRAMEWORK_VERSION}) + string(REGEX REPLACE ${RE} "\\2" ORTHANC_FRAMEWORK_MINOR ${ORTHANC_FRAMEWORK_VERSION}) + string(REGEX REPLACE ${RE} "\\3" ORTHANC_FRAMEWORK_REVISION ${ORTHANC_FRAMEWORK_VERSION}) + + if (NOT ORTHANC_FRAMEWORK_MAJOR MATCHES "^[0-9]+$" OR + NOT ORTHANC_FRAMEWORK_MINOR MATCHES "^[0-9]+$" OR + NOT ORTHANC_FRAMEWORK_REVISION MATCHES "^[0-9]+$") + message("Bad version of the Orthanc framework: ${ORTHANC_FRAMEWORK_VERSION}") + endif() + + if (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.1") + set(ORTHANC_FRAMEWORK_MD5 "dac95bd6cf86fb19deaf4e612961f378") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.2") + set(ORTHANC_FRAMEWORK_MD5 "d0ccdf68e855d8224331f13774992750") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.0") + set(ORTHANC_FRAMEWORK_MD5 "81e15f34d97ac32bbd7d26e85698835a") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.1") + set(ORTHANC_FRAMEWORK_MD5 "9b6f6114264b17ed421b574cd6476127") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.2") + set(ORTHANC_FRAMEWORK_MD5 "d1ee84927dcf668e60eb5868d24b9394") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.0") + set(ORTHANC_FRAMEWORK_MD5 "4429d8d9dea4ff6648df80ec3c64d79e") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.1") + set(ORTHANC_FRAMEWORK_MD5 "099671538865e5da96208b37494d6718") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.2") + set(ORTHANC_FRAMEWORK_MD5 "8867050f3e9a1ce6157c1ea7a9433b1b") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.3") + set(ORTHANC_FRAMEWORK_MD5 "bf2f5ed1adb8b0fc5f10d278e68e1dfe") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.4") + set(ORTHANC_FRAMEWORK_MD5 "404baef5d4c43e7c5d9410edda8ef5a5") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.5") + set(ORTHANC_FRAMEWORK_MD5 "cfc437e0687ae4bd725fd93dc1f08bc4") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.6") + set(ORTHANC_FRAMEWORK_MD5 "3c29de1e289b5472342947168f0105c0") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.7") + set(ORTHANC_FRAMEWORK_MD5 "e1b76f01116d9b5d4ac8cc39980560e3") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.8") + set(ORTHANC_FRAMEWORK_MD5 "82323e8c49a667f658a3639ea4dbc336") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.6.0") + set(ORTHANC_FRAMEWORK_MD5 "eab428d6e53f61e847fa360bb17ebe25") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.6.1") + set(ORTHANC_FRAMEWORK_MD5 "3971f5de96ba71dc9d3f3690afeaa7c0") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.7.0") + set(ORTHANC_FRAMEWORK_MD5 "ce5f689e852b01d3672bd3d2f952a5ef") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.7.1") + set(ORTHANC_FRAMEWORK_MD5 "3c171217f930abe80246997bdbcaf7cc") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.7.2") + set(ORTHANC_FRAMEWORK_MD5 "328f94dcbd78c169655a13f7ad58a2c2") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.7.3") + set(ORTHANC_FRAMEWORK_MD5 "3f1ba9502ec7c5449971d3b56087bcde") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.7.4") + set(ORTHANC_FRAMEWORK_MD5 "19fcb7c21876af86546baa048a22c6c0") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.8.0") + set(ORTHANC_FRAMEWORK_MD5 "f8ec7554ef5d23ea4ce474b1e8214de9") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.8.1") + set(ORTHANC_FRAMEWORK_MD5 "db094f96399cbe8b9bbdbce34884c220") + + # Below this point are development snapshots that were used to + # release some plugin, before an official release of the Orthanc + # framework was available. Here is the command to be used to + # generate a proper archive: + # + # $ hg archive /tmp/Orthanc-`hg id -i | sed 's/\+//'`.tar.gz + # + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "ae0e3fd609df") + # DICOMweb 1.1 (framework pre-1.6.0) + set(ORTHANC_FRAMEWORK_MD5 "7e09e9b530a2f527854f0b782d7e0645") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "82652c5fc04f") + # Stone Web viewer 1.0 (framework pre-1.8.1) + set(ORTHANC_FRAMEWORK_MD5 "d77331d68917e66a3f4f9b807bbdab7f") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "4a3ba4bf4ba7") + # PostgreSQL 3.3 (framework pre-1.8.2) + set(ORTHANC_FRAMEWORK_MD5 "2d82bddf06f9cfe82095495cb3b8abde") + endif() + endif() + endif() + +elseif (ORTHANC_FRAMEWORK_SOURCE STREQUAL "path") + message("Using the Orthanc framework from a path of the filesystem. Assuming mainline version.") + set(ORTHANC_FRAMEWORK_MAJOR 999) + set(ORTHANC_FRAMEWORK_MINOR 999) + set(ORTHANC_FRAMEWORK_REVISION 999) +endif() + + + +## +## Detection of the third-party software +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg") + find_program(ORTHANC_FRAMEWORK_HG hg) + + if (${ORTHANC_FRAMEWORK_HG} MATCHES "ORTHANC_FRAMEWORK_HG-NOTFOUND") + message(FATAL_ERROR "Please install Mercurial") + endif() +endif() + + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR + ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") + if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + find_program(ORTHANC_FRAMEWORK_7ZIP 7z + PATHS + "$ENV{ProgramFiles}/7-Zip" + "$ENV{ProgramW6432}/7-Zip" + ) + + if (${ORTHANC_FRAMEWORK_7ZIP} MATCHES "ORTHANC_FRAMEWORK_7ZIP-NOTFOUND") + message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") + endif() + + else() + find_program(ORTHANC_FRAMEWORK_TAR tar) + if (${ORTHANC_FRAMEWORK_TAR} MATCHES "ORTHANC_FRAMEWORK_TAR-NOTFOUND") + message(FATAL_ERROR "Please install the 'tar' package") + endif() + endif() +endif() + + + +## +## Case of the Orthanc framework specified as a path on the filesystem +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "path") + if (NOT DEFINED ORTHANC_FRAMEWORK_ROOT OR + ORTHANC_FRAMEWORK_ROOT STREQUAL "") + message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_ROOT must provide the path to the sources of Orthanc") + endif() + + if (NOT EXISTS ${ORTHANC_FRAMEWORK_ROOT}) + message(FATAL_ERROR "Non-existing directory: ${ORTHANC_FRAMEWORK_ROOT}") + endif() +endif() + + + +## +## Case of the Orthanc framework cloned using Mercurial +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg") + if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) + message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") + endif() + + set(ORTHANC_ROOT ${CMAKE_BINARY_DIR}/orthanc) + + if (EXISTS ${ORTHANC_ROOT}) + message("Updating the Orthanc source repository using Mercurial") + execute_process( + COMMAND ${ORTHANC_FRAMEWORK_HG} pull + WORKING_DIRECTORY ${ORTHANC_ROOT} + RESULT_VARIABLE Failure + ) + else() + message("Forking the Orthanc source repository using Mercurial") + execute_process( + COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://hg.orthanc-server.com/orthanc/" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + endif() + + if (Failure OR NOT EXISTS ${ORTHANC_ROOT}) + message(FATAL_ERROR "Cannot fork the Orthanc repository") + endif() + + message("Setting branch of the Orthanc repository to: ${ORTHANC_FRAMEWORK_BRANCH}") + + execute_process( + COMMAND ${ORTHANC_FRAMEWORK_HG} update -c ${ORTHANC_FRAMEWORK_BRANCH} + WORKING_DIRECTORY ${ORTHANC_ROOT} + RESULT_VARIABLE Failure + ) + + if (Failure) + message(FATAL_ERROR "Error while running Mercurial") + endif() +endif() + + + +## +## Case of the Orthanc framework provided as a source archive on the +## filesystem +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive") + if (NOT DEFINED ORTHANC_FRAMEWORK_ARCHIVE OR + ORTHANC_FRAMEWORK_ARCHIVE STREQUAL "") + message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_ARCHIVE must provide the path to the sources of Orthanc") + endif() +endif() + + + +## +## Case of the Orthanc framework downloaded from the Web +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") + if (DEFINED ORTHANC_FRAMEWORK_URL) + string(REGEX REPLACE "^.*/" "" ORTHANC_FRAMEMORK_FILENAME "${ORTHANC_FRAMEWORK_URL}") + else() + # Default case: Download from the official Web site + set(ORTHANC_FRAMEMORK_FILENAME Orthanc-${ORTHANC_FRAMEWORK_VERSION}.tar.gz) + set(ORTHANC_FRAMEWORK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/orthanc-framework/${ORTHANC_FRAMEMORK_FILENAME}") + endif() + + set(ORTHANC_FRAMEWORK_ARCHIVE "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${ORTHANC_FRAMEMORK_FILENAME}") + + if (NOT EXISTS "${ORTHANC_FRAMEWORK_ARCHIVE}") + if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) + message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") + endif() + + message("Downloading: ${ORTHANC_FRAMEWORK_URL}") + + file(DOWNLOAD + "${ORTHANC_FRAMEWORK_URL}" "${ORTHANC_FRAMEWORK_ARCHIVE}" + SHOW_PROGRESS EXPECTED_MD5 "${ORTHANC_FRAMEWORK_MD5}" + TIMEOUT 60 + INACTIVITY_TIMEOUT 60 + ) + else() + message("Using local copy of: ${ORTHANC_FRAMEWORK_URL}") + endif() +endif() + + + + +## +## Uncompressing the Orthanc framework, if it was retrieved from a +## source archive on the filesystem, or from the official Web site +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR + ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") + + if (NOT DEFINED ORTHANC_FRAMEWORK_ARCHIVE OR + NOT DEFINED ORTHANC_FRAMEWORK_VERSION OR + NOT DEFINED ORTHANC_FRAMEWORK_MD5) + message(FATAL_ERROR "Internal error") + endif() + + if (ORTHANC_FRAMEWORK_MD5 STREQUAL "") + message(FATAL_ERROR "Unknown release of Orthanc: ${ORTHANC_FRAMEWORK_VERSION}") + endif() + + file(MD5 ${ORTHANC_FRAMEWORK_ARCHIVE} ActualMD5) + + if (NOT "${ActualMD5}" STREQUAL "${ORTHANC_FRAMEWORK_MD5}") + message(FATAL_ERROR "The MD5 hash of the Orthanc archive is invalid: ${ORTHANC_FRAMEWORK_ARCHIVE}") + endif() + + set(ORTHANC_ROOT "${CMAKE_BINARY_DIR}/Orthanc-${ORTHANC_FRAMEWORK_VERSION}") + + if (NOT IS_DIRECTORY "${ORTHANC_ROOT}") + if (NOT ORTHANC_FRAMEWORK_ARCHIVE MATCHES ".tar.gz$") + message(FATAL_ERROR "Archive should have the \".tar.gz\" extension: ${ORTHANC_FRAMEWORK_ARCHIVE}") + endif() + + message("Uncompressing: ${ORTHANC_FRAMEWORK_ARCHIVE}") + + if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + # How to silently extract files using 7-zip + # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly + + execute_process( + COMMAND ${ORTHANC_FRAMEWORK_7ZIP} e -y ${ORTHANC_FRAMEWORK_ARCHIVE} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + get_filename_component(TMP_FILENAME "${ORTHANC_FRAMEWORK_ARCHIVE}" NAME) + string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") + + execute_process( + COMMAND ${ORTHANC_FRAMEWORK_7ZIP} x -y ${TMP_FILENAME2} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + + else() + execute_process( + COMMAND sh -c "${ORTHANC_FRAMEWORK_TAR} xfz ${ORTHANC_FRAMEWORK_ARCHIVE}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + endif() + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + if (NOT IS_DIRECTORY "${ORTHANC_ROOT}") + message(FATAL_ERROR "The Orthanc framework was not uncompressed at the proper location. Check the CMake instructions.") + endif() + endif() +endif() + + + +## +## Determine the path to the sources of the Orthanc framework +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR + ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" OR + ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") + if (NOT DEFINED ORTHANC_ROOT OR + NOT DEFINED ORTHANC_FRAMEWORK_MAJOR OR + NOT DEFINED ORTHANC_FRAMEWORK_MINOR OR + NOT DEFINED ORTHANC_FRAMEWORK_REVISION) + message(FATAL_ERROR "Internal error in the DownloadOrthancFramework.cmake file") + endif() + + unset(ORTHANC_FRAMEWORK_ROOT CACHE) + + if ("${ORTHANC_FRAMEWORK_MAJOR}.${ORTHANC_FRAMEWORK_MINOR}.${ORTHANC_FRAMEWORK_REVISION}" VERSION_LESS "1.7.2") + set(ORTHANC_FRAMEWORK_ROOT "${ORTHANC_ROOT}/Core" CACHE + STRING "Path to the Orthanc framework source directory") + set(ENABLE_PLUGINS_VERSION_SCRIPT OFF) + else() + set(ORTHANC_FRAMEWORK_ROOT "${ORTHANC_ROOT}/OrthancFramework/Sources" CACHE + STRING "Path to the Orthanc framework source directory") + endif() + + unset(ORTHANC_ROOT) +endif() + +if (NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "system") + if (NOT EXISTS ${ORTHANC_FRAMEWORK_ROOT}/OrthancException.h OR + NOT EXISTS ${ORTHANC_FRAMEWORK_ROOT}/../Resources/CMake/OrthancFrameworkParameters.cmake) + message(FATAL_ERROR "Directory not containing the source code of the Orthanc framework: ${ORTHANC_FRAMEWORK_ROOT}") + endif() +endif() + + + +## +## Case of the Orthanc framework installed as a shared library in a +## GNU/Linux distribution (typically Debian). New in Orthanc 1.7.2. +## + +if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "system") + set(ORTHANC_FRAMEWORK_LIBDIR "" CACHE PATH "") + + if (CMAKE_SYSTEM_NAME STREQUAL "Windows" AND + CMAKE_COMPILER_IS_GNUCXX) # MinGW + set(DYNAMIC_MINGW_STDLIB ON) # Disable static linking against libc (to throw exceptions) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libstdc++") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++") + endif() + + include(CheckIncludeFile) + include(CheckIncludeFileCXX) + include(FindPythonInterp) + include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/DownloadPackage.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake) + set(EMBED_RESOURCES_PYTHON ${CMAKE_CURRENT_LIST_DIR}/EmbedResources.py) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" OR + ORTHANC_FRAMEWORK_STATIC) + include_directories(${ORTHANC_FRAMEWORK_ROOT}/..) + else() + # Look for mandatory dependency JsonCpp (cf. JsonCppConfiguration.cmake) + find_path(JSONCPP_INCLUDE_DIR json/reader.h + /usr/include/jsoncpp + /usr/local/include/jsoncpp + ) + + message("JsonCpp include dir: ${JSONCPP_INCLUDE_DIR}") + include_directories(${JSONCPP_INCLUDE_DIR}) + link_libraries(jsoncpp) + + CHECK_INCLUDE_FILE_CXX(${JSONCPP_INCLUDE_DIR}/json/reader.h HAVE_JSONCPP_H) + if (NOT HAVE_JSONCPP_H) + message(FATAL_ERROR "Please install the libjsoncpp-dev package") + endif() + + # Switch to the C++11 standard if the version of JsonCpp is 1.y.z + # (same as variable JSONCPP_CXX11 in the source code of Orthanc) + if (EXISTS ${JSONCPP_INCLUDE_DIR}/json/version.h) + file(STRINGS + "${JSONCPP_INCLUDE_DIR}/json/version.h" + JSONCPP_VERSION_MAJOR1 REGEX + ".*define JSONCPP_VERSION_MAJOR.*") + + if (NOT JSONCPP_VERSION_MAJOR1) + message(FATAL_ERROR "Unable to extract the major version of JsonCpp") + endif() + + string(REGEX REPLACE + ".*JSONCPP_VERSION_MAJOR.*([0-9]+)$" "\\1" + JSONCPP_VERSION_MAJOR ${JSONCPP_VERSION_MAJOR1}) + message("JsonCpp major version: ${JSONCPP_VERSION_MAJOR}") + + if (JSONCPP_VERSION_MAJOR GREATER 0) + message("Switching to C++11 standard, as version of JsonCpp is >= 1.0.0") + if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() + endif() + else() + message("Unable to detect the major version of JsonCpp, assuming < 1.0.0") + endif() + + # Look for mandatory dependency Boost (cf. BoostConfiguration.cmake) + include(FindBoost) + find_package(Boost COMPONENTS filesystem thread system date_time regex ${ORTHANC_BOOST_COMPONENTS}) + + if (NOT Boost_FOUND) + message(FATAL_ERROR "Unable to locate Boost on this system") + endif() + + include_directories(${Boost_INCLUDE_DIRS}) + link_libraries(${Boost_LIBRARIES}) + + # Optional component - Lua + if (ENABLE_LUA) + include(FindLua) + + if (NOT LUA_FOUND) + message(FATAL_ERROR "Please install the liblua-dev package") + endif() + + include_directories(${LUA_INCLUDE_DIR}) + link_libraries(${LUA_LIBRARIES}) + endif() + + # Optional component - SQLite + if (ENABLE_SQLITE) + CHECK_INCLUDE_FILE(sqlite3.h HAVE_SQLITE_H) + if (NOT HAVE_SQLITE_H) + message(FATAL_ERROR "Please install the libsqlite3-dev package") + endif() + link_libraries(sqlite3) + endif() + + # Optional component - Pugixml + if (ENABLE_PUGIXML) + CHECK_INCLUDE_FILE_CXX(pugixml.hpp HAVE_PUGIXML_H) + if (NOT HAVE_PUGIXML_H) + message(FATAL_ERROR "Please install the libpugixml-dev package") + endif() + link_libraries(pugixml) + endif() + + # Optional component - DCMTK + if (ENABLE_DCMTK) + include(FindDCMTK) + include_directories(${DCMTK_INCLUDE_DIRS}) + link_libraries(${DCMTK_LIBRARIES}) + endif() + + # Optional component - OpenSSL + if (ENABLE_SSL) + include(FindOpenSSL) + if (NOT ${OPENSSL_FOUND}) + message(FATAL_ERROR "Unable to find OpenSSL") + endif() + include_directories(${OPENSSL_INCLUDE_DIR}) + link_libraries(${OPENSSL_LIBRARIES}) + endif() + endif() + + # Look for Orthanc framework shared library + include(CheckCXXSymbolExists) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + set(ORTHANC_FRAMEWORK_INCLUDE_DIR ${ORTHANC_FRAMEWORK_ROOT}) + else() + find_path(ORTHANC_FRAMEWORK_INCLUDE_DIR OrthancFramework.h + /usr/include/orthanc-framework + /usr/local/include/orthanc-framework + ${ORTHANC_FRAMEWORK_ROOT} + ) + endif() + + if (${ORTHANC_FRAMEWORK_INCLUDE_DIR} STREQUAL "ORTHANC_FRAMEWORK_INCLUDE_DIR-NOTFOUND") + message(FATAL_ERROR "Cannot locate the OrthancFramework.h header") + endif() + + message("Orthanc framework include dir: ${ORTHANC_FRAMEWORK_INCLUDE_DIR}") + include_directories(${ORTHANC_FRAMEWORK_INCLUDE_DIR}) + + if ("${ORTHANC_FRAMEWORK_LIBDIR}" STREQUAL "") + set(ORTHANC_FRAMEWORK_LIBRARIES OrthancFramework) + else() + if (MSVC) + set(Suffix ".lib") + set(Prefix "") + else() + list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix) + list(GET CMAKE_FIND_LIBRARY_SUFFIXES 0 Suffix) + endif() + set(ORTHANC_FRAMEWORK_LIBRARIES ${ORTHANC_FRAMEWORK_LIBDIR}/${Prefix}OrthancFramework${Suffix}) + endif() + + set(CMAKE_REQUIRED_INCLUDES "${ORTHANC_FRAMEWORK_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${ORTHANC_FRAMEWORK_LIBRARIES}") + + check_cxx_symbol_exists("Orthanc::InitializeFramework" "OrthancFramework.h" HAVE_ORTHANC_FRAMEWORK) + if (NOT HAVE_ORTHANC_FRAMEWORK) + message(FATAL_ERROR "Cannot find the Orthanc framework") + endif() + + unset(CMAKE_REQUIRED_INCLUDES) + unset(CMAKE_REQUIRED_LIBRARIES) +endif() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/CMake/DownloadPackage.cmake orthanc-mysql-3.0/Resources/Orthanc/CMake/DownloadPackage.cmake --- orthanc-mysql-2.0/Resources/Orthanc/CMake/DownloadPackage.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/CMake/DownloadPackage.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,278 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +macro(GetUrlFilename TargetVariable Url) + string(REGEX REPLACE "^.*/" "" ${TargetVariable} "${Url}") +endmacro() + + +macro(GetUrlExtension TargetVariable Url) + #string(REGEX REPLACE "^.*/[^.]*\\." "" TMP "${Url}") + string(REGEX REPLACE "^.*\\." "" TMP "${Url}") + string(TOLOWER "${TMP}" "${TargetVariable}") +endmacro() + + + +## +## Setup the patch command-line tool +## + +if (NOT ORTHANC_DISABLE_PATCH) + if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe) + if (NOT EXISTS ${PATCH_EXECUTABLE}) + message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc") + endif() + + else () + find_program(PATCH_EXECUTABLE patch) + if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'patch' standard command-line tool") + endif() + endif() +endif() + + + +## +## Check the existence of the required decompression tools +## + +if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + find_program(ZIP_EXECUTABLE 7z + PATHS + "$ENV{ProgramFiles}/7-Zip" + "$ENV{ProgramW6432}/7-Zip" + ) + + if (${ZIP_EXECUTABLE} MATCHES "ZIP_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") + endif() + +else() + find_program(UNZIP_EXECUTABLE unzip) + if (${UNZIP_EXECUTABLE} MATCHES "UNZIP_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'unzip' package") + endif() + + find_program(TAR_EXECUTABLE tar) + if (${TAR_EXECUTABLE} MATCHES "TAR_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'tar' package") + endif() + + find_program(GUNZIP_EXECUTABLE gunzip) + if (${GUNZIP_EXECUTABLE} MATCHES "GUNZIP_EXECUTABLE-NOTFOUND") + message(FATAL_ERROR "Please install the 'gzip' package") + endif() +endif() + + +macro(DownloadFile MD5 Url) + GetUrlFilename(TMP_FILENAME "${Url}") + + set(TMP_PATH "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${TMP_FILENAME}") + if (NOT EXISTS "${TMP_PATH}") + message("Downloading ${Url}") + + # This fixes issue 6: "I think cmake shouldn't download the + # packages which are not in the system, it should stop and let + # user know." + # https://code.google.com/p/orthanc/issues/detail?id=6 + if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) + message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") + endif() + + if ("${MD5}" STREQUAL "no-check") + message(WARNING "Not checking the MD5 of: ${Url}") + file(DOWNLOAD "${Url}" "${TMP_PATH}" + SHOW_PROGRESS TIMEOUT 300 INACTIVITY_TIMEOUT 60 + STATUS Failure) + else() + file(DOWNLOAD "${Url}" "${TMP_PATH}" + SHOW_PROGRESS TIMEOUT 300 INACTIVITY_TIMEOUT 60 + EXPECTED_MD5 "${MD5}" STATUS Failure) + endif() + + list(GET Failure 0 Status) + if (NOT Status EQUAL 0) + message(FATAL_ERROR "Cannot download file: ${Url}") + endif() + + else() + message("Using local copy of ${Url}") + + if ("${MD5}" STREQUAL "no-check") + message(WARNING "Not checking the MD5 of: ${Url}") + else() + file(MD5 ${TMP_PATH} ActualMD5) + if (NOT "${ActualMD5}" STREQUAL "${MD5}") + message(FATAL_ERROR "The MD5 hash of a previously download file is invalid: ${TMP_PATH}") + endif() + endif() + endif() +endmacro() + + +macro(DownloadPackage MD5 Url TargetDirectory) + if (NOT IS_DIRECTORY "${TargetDirectory}") + DownloadFile("${MD5}" "${Url}") + + GetUrlExtension(TMP_EXTENSION "${Url}") + #message(${TMP_EXTENSION}) + message("Uncompressing ${TMP_FILENAME}") + + if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + # How to silently extract files using 7-zip + # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly + + if (("${TMP_EXTENSION}" STREQUAL "gz") OR + ("${TMP_EXTENSION}" STREQUAL "tgz") OR + ("${TMP_EXTENSION}" STREQUAL "xz")) + execute_process( + COMMAND ${ZIP_EXECUTABLE} e -y ${TMP_PATH} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + if ("${TMP_EXTENSION}" STREQUAL "tgz") + string(REGEX REPLACE ".tgz$" ".tar" TMP_FILENAME2 "${TMP_FILENAME}") + elseif ("${TMP_EXTENSION}" STREQUAL "gz") + string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") + elseif ("${TMP_EXTENSION}" STREQUAL "xz") + string(REGEX REPLACE ".xz" "" TMP_FILENAME2 "${TMP_FILENAME}") + endif() + + execute_process( + COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_FILENAME2} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + elseif ("${TMP_EXTENSION}" STREQUAL "zip") + execute_process( + COMMAND ${ZIP_EXECUTABLE} x -y ${TMP_PATH} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + else() + message(FATAL_ERROR "Unsupported package extension: ${TMP_EXTENSION}") + endif() + + else() + if ("${TMP_EXTENSION}" STREQUAL "zip") + execute_process( + COMMAND sh -c "${UNZIP_EXECUTABLE} -q ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + elseif (("${TMP_EXTENSION}" STREQUAL "gz") OR ("${TMP_EXTENSION}" STREQUAL "tgz")) + #message("tar xvfz ${TMP_PATH}") + execute_process( + COMMAND sh -c "${TAR_EXECUTABLE} xfz ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + elseif ("${TMP_EXTENSION}" STREQUAL "bz2") + execute_process( + COMMAND sh -c "${TAR_EXECUTABLE} xfj ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + elseif ("${TMP_EXTENSION}" STREQUAL "xz") + execute_process( + COMMAND sh -c "${TAR_EXECUTABLE} xf ${TMP_PATH}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + else() + message(FATAL_ERROR "Unsupported package extension: ${TMP_EXTENSION}") + endif() + endif() + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + if (NOT IS_DIRECTORY "${TargetDirectory}") + message(FATAL_ERROR "The package was not uncompressed at the proper location. Check the CMake instructions.") + endif() + endif() +endmacro() + + + +macro(DownloadCompressedFile MD5 Url TargetFile) + if (NOT EXISTS "${TargetFile}") + DownloadFile("${MD5}" "${Url}") + + GetUrlExtension(TMP_EXTENSION "${Url}") + #message(${TMP_EXTENSION}) + message("Uncompressing ${TMP_FILENAME}") + + if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") + # How to silently extract files using 7-zip + # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly + + if ("${TMP_EXTENSION}" STREQUAL "gz") + execute_process( + # "-so" writes uncompressed file to stdout + COMMAND ${ZIP_EXECUTABLE} e -so -y ${TMP_PATH} + OUTPUT_FILE "${TargetFile}" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + OUTPUT_QUIET + ) + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + else() + message(FATAL_ERROR "Unsupported file extension: ${TMP_EXTENSION}") + endif() + + else() + if ("${TMP_EXTENSION}" STREQUAL "gz") + execute_process( + COMMAND sh -c "${GUNZIP_EXECUTABLE} -c ${TMP_PATH}" + OUTPUT_FILE "${TargetFile}" + RESULT_VARIABLE Failure + ) + else() + message(FATAL_ERROR "Unsupported file extension: ${TMP_EXTENSION}") + endif() + endif() + + if (Failure) + message(FATAL_ERROR "Error while running the uncompression tool") + endif() + + if (NOT EXISTS "${TargetFile}") + message(FATAL_ERROR "The file was not uncompressed at the proper location. Check the CMake instructions.") + endif() + endif() +endmacro() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake orthanc-mysql-3.0/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake --- orthanc-mysql-2.0/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/CMake/GoogleTestConfiguration.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,89 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +if (USE_GOOGLE_TEST_DEBIAN_PACKAGE) + find_path(GOOGLE_TEST_DEBIAN_SOURCES_DIR + NAMES src/gtest-all.cc + PATHS + ${CROSSTOOL_NG_IMAGE}/usr/src/gtest + ${CROSSTOOL_NG_IMAGE}/usr/src/googletest/googletest + PATH_SUFFIXES src + ) + + find_path(GOOGLE_TEST_DEBIAN_INCLUDE_DIR + NAMES gtest.h + PATHS + ${CROSSTOOL_NG_IMAGE}/usr/include/gtest + ) + + message("Path to the Debian Google Test sources: ${GOOGLE_TEST_DEBIAN_SOURCES_DIR}") + message("Path to the Debian Google Test includes: ${GOOGLE_TEST_DEBIAN_INCLUDE_DIR}") + + set(GOOGLE_TEST_SOURCES + ${GOOGLE_TEST_DEBIAN_SOURCES_DIR}/src/gtest-all.cc + ) + + include_directories(${GOOGLE_TEST_DEBIAN_SOURCES_DIR}) + + if (NOT EXISTS ${GOOGLE_TEST_SOURCES} OR + NOT EXISTS ${GOOGLE_TEST_DEBIAN_INCLUDE_DIR}/gtest.h) + message(FATAL_ERROR "Please install the libgtest-dev package") + endif() + +elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST) + set(GOOGLE_TEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/googletest-release-1.8.1) + set(GOOGLE_TEST_URL "http://orthanc.osimis.io/ThirdPartyDownloads/gtest-1.8.1.tar.gz") + set(GOOGLE_TEST_MD5 "2e6fbeb6a91310a16efe181886c59596") + + DownloadPackage(${GOOGLE_TEST_MD5} ${GOOGLE_TEST_URL} "${GOOGLE_TEST_SOURCES_DIR}") + + include_directories( + ${GOOGLE_TEST_SOURCES_DIR}/googletest + ${GOOGLE_TEST_SOURCES_DIR}/googletest/include + ${GOOGLE_TEST_SOURCES_DIR} + ) + + set(GOOGLE_TEST_SOURCES + ${GOOGLE_TEST_SOURCES_DIR}/googletest/src/gtest-all.cc + ) + + # https://code.google.com/p/googletest/issues/detail?id=412 + if (MSVC) # VS2012 does not support tuples correctly yet + add_definitions(/D _VARIADIC_MAX=10) + endif() + + if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + add_definitions(-DGTEST_HAS_CLONE=0) + endif() + + source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GOOGLE_TEST_SOURCES_DIR}/.*) + +else() + include(FindGTest) + if (NOT GTEST_FOUND) + message(FATAL_ERROR "Unable to find GoogleTest") + endif() + + include_directories(${GTEST_INCLUDE_DIRS}) + + # The variable GTEST_LIBRARIES contains the shared library of + # Google Test, create an alias for more uniformity + set(GOOGLE_TEST_LIBRARIES ${GTEST_LIBRARIES}) +endif() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Databases/DatabaseConstraint.cpp orthanc-mysql-3.0/Resources/Orthanc/Databases/DatabaseConstraint.cpp --- orthanc-mysql-2.0/Resources/Orthanc/Databases/DatabaseConstraint.cpp 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Databases/DatabaseConstraint.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,258 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#if !defined(ORTHANC_BUILDING_SERVER_LIBRARY) +# error Macro ORTHANC_BUILDING_SERVER_LIBRARY must be defined +#endif + +#if ORTHANC_BUILDING_SERVER_LIBRARY == 1 +# include "../PrecompiledHeadersServer.h" +#endif + +#include "DatabaseConstraint.h" + +#if ORTHANC_BUILDING_SERVER_LIBRARY == 1 +# include "../../../OrthancFramework/Sources/OrthancException.h" +#else +# include +#endif + +#include + + +namespace Orthanc +{ + namespace Plugins + { +#if ORTHANC_ENABLE_PLUGINS == 1 + OrthancPluginResourceType Convert(ResourceType type) + { + switch (type) + { + case ResourceType_Patient: + return OrthancPluginResourceType_Patient; + + case ResourceType_Study: + return OrthancPluginResourceType_Study; + + case ResourceType_Series: + return OrthancPluginResourceType_Series; + + case ResourceType_Instance: + return OrthancPluginResourceType_Instance; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } +#endif + + +#if ORTHANC_ENABLE_PLUGINS == 1 + ResourceType Convert(OrthancPluginResourceType type) + { + switch (type) + { + case OrthancPluginResourceType_Patient: + return ResourceType_Patient; + + case OrthancPluginResourceType_Study: + return ResourceType_Study; + + case OrthancPluginResourceType_Series: + return ResourceType_Series; + + case OrthancPluginResourceType_Instance: + return ResourceType_Instance; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } +#endif + + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + OrthancPluginConstraintType Convert(ConstraintType constraint) + { + switch (constraint) + { + case ConstraintType_Equal: + return OrthancPluginConstraintType_Equal; + + case ConstraintType_GreaterOrEqual: + return OrthancPluginConstraintType_GreaterOrEqual; + + case ConstraintType_SmallerOrEqual: + return OrthancPluginConstraintType_SmallerOrEqual; + + case ConstraintType_Wildcard: + return OrthancPluginConstraintType_Wildcard; + + case ConstraintType_List: + return OrthancPluginConstraintType_List; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } +#endif + + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + ConstraintType Convert(OrthancPluginConstraintType constraint) + { + switch (constraint) + { + case OrthancPluginConstraintType_Equal: + return ConstraintType_Equal; + + case OrthancPluginConstraintType_GreaterOrEqual: + return ConstraintType_GreaterOrEqual; + + case OrthancPluginConstraintType_SmallerOrEqual: + return ConstraintType_SmallerOrEqual; + + case OrthancPluginConstraintType_Wildcard: + return ConstraintType_Wildcard; + + case OrthancPluginConstraintType_List: + return ConstraintType_List; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } +#endif + } + + DatabaseConstraint::DatabaseConstraint(ResourceType level, + const DicomTag& tag, + bool isIdentifier, + ConstraintType type, + const std::vector& values, + bool caseSensitive, + bool mandatory) : + level_(level), + tag_(tag), + isIdentifier_(isIdentifier), + constraintType_(type), + values_(values), + caseSensitive_(caseSensitive), + mandatory_(mandatory) + { + if (type != ConstraintType_List && + values_.size() != 1) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + DatabaseConstraint::DatabaseConstraint(const OrthancPluginDatabaseConstraint& constraint) : + level_(Plugins::Convert(constraint.level)), + tag_(constraint.tagGroup, constraint.tagElement), + isIdentifier_(constraint.isIdentifierTag), + constraintType_(Plugins::Convert(constraint.type)), + caseSensitive_(constraint.isCaseSensitive), + mandatory_(constraint.isMandatory) + { + if (constraintType_ != ConstraintType_List && + constraint.valuesCount != 1) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + values_.resize(constraint.valuesCount); + + for (uint32_t i = 0; i < constraint.valuesCount; i++) + { + assert(constraint.values[i] != NULL); + values_[i].assign(constraint.values[i]); + } + } +#endif + + + const std::string& DatabaseConstraint::GetValue(size_t index) const + { + if (index >= values_.size()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + else + { + return values_[index]; + } + } + + + const std::string& DatabaseConstraint::GetSingleValue() const + { + if (values_.size() != 1) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + else + { + return values_[0]; + } + } + + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + void DatabaseConstraint::EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, + std::vector& tmpValues) const + { + memset(&constraint, 0, sizeof(constraint)); + + tmpValues.resize(values_.size()); + + for (size_t i = 0; i < values_.size(); i++) + { + tmpValues[i] = values_[i].c_str(); + } + + constraint.level = Plugins::Convert(level_); + constraint.tagGroup = tag_.GetGroup(); + constraint.tagElement = tag_.GetElement(); + constraint.isIdentifierTag = isIdentifier_; + constraint.isCaseSensitive = caseSensitive_; + constraint.isMandatory = mandatory_; + constraint.type = Plugins::Convert(constraintType_); + constraint.valuesCount = values_.size(); + constraint.values = (tmpValues.empty() ? NULL : &tmpValues[0]); + } +#endif +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Databases/DatabaseConstraint.h orthanc-mysql-3.0/Resources/Orthanc/Databases/DatabaseConstraint.h --- orthanc-mysql-2.0/Resources/Orthanc/Databases/DatabaseConstraint.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Databases/DatabaseConstraint.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,161 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#if !defined(ORTHANC_BUILDING_SERVER_LIBRARY) +# error Macro ORTHANC_BUILDING_SERVER_LIBRARY must be defined +#endif + +#if ORTHANC_BUILDING_SERVER_LIBRARY == 1 +# include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" +#else +// This is for the "orthanc-databases" project to reuse this file +# include +#endif + +#define ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT 0 + +#if ORTHANC_ENABLE_PLUGINS == 1 +# include +# if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 2) +# undef ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT +# define ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT 1 +# endif +# endif +#endif + +namespace Orthanc +{ + enum ConstraintType + { + ConstraintType_Equal, + ConstraintType_SmallerOrEqual, + ConstraintType_GreaterOrEqual, + ConstraintType_Wildcard, + ConstraintType_List + }; + + namespace Plugins + { +#if ORTHANC_ENABLE_PLUGINS == 1 + OrthancPluginResourceType Convert(ResourceType type); +#endif + +#if ORTHANC_ENABLE_PLUGINS == 1 + ResourceType Convert(OrthancPluginResourceType type); +#endif + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + OrthancPluginConstraintType Convert(ConstraintType constraint); +#endif + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + ConstraintType Convert(OrthancPluginConstraintType constraint); +#endif + } + + + // This class is also used by the "orthanc-databases" project + class DatabaseConstraint + { + private: + ResourceType level_; + DicomTag tag_; + bool isIdentifier_; + ConstraintType constraintType_; + std::vector values_; + bool caseSensitive_; + bool mandatory_; + + public: + DatabaseConstraint(ResourceType level, + const DicomTag& tag, + bool isIdentifier, + ConstraintType type, + const std::vector& values, + bool caseSensitive, + bool mandatory); + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + explicit DatabaseConstraint(const OrthancPluginDatabaseConstraint& constraint); +#endif + + ResourceType GetLevel() const + { + return level_; + } + + const DicomTag& GetTag() const + { + return tag_; + } + + bool IsIdentifier() const + { + return isIdentifier_; + } + + ConstraintType GetConstraintType() const + { + return constraintType_; + } + + size_t GetValuesCount() const + { + return values_.size(); + } + + const std::string& GetValue(size_t index) const; + + const std::string& GetSingleValue() const; + + bool IsCaseSensitive() const + { + return caseSensitive_; + } + + bool IsMandatory() const + { + return mandatory_; + } + + bool IsMatch(const DicomMap& dicom) const; + +#if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 + void EncodeForPlugins(OrthancPluginDatabaseConstraint& constraint, + std::vector& tmpValues) const; +#endif + }; +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Databases/ISqlLookupFormatter.cpp orthanc-mysql-3.0/Resources/Orthanc/Databases/ISqlLookupFormatter.cpp --- orthanc-mysql-2.0/Resources/Orthanc/Databases/ISqlLookupFormatter.cpp 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Databases/ISqlLookupFormatter.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,358 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#if !defined(ORTHANC_BUILDING_SERVER_LIBRARY) +# error Macro ORTHANC_BUILDING_SERVER_LIBRARY must be defined +#endif + +#if ORTHANC_BUILDING_SERVER_LIBRARY == 1 +# include "../PrecompiledHeadersServer.h" +#endif + +#include "ISqlLookupFormatter.h" + +#if ORTHANC_BUILDING_SERVER_LIBRARY == 1 +# include "../../../OrthancFramework/Sources/OrthancException.h" +#else +# include +#endif + +#include "DatabaseConstraint.h" + +#include + + +namespace Orthanc +{ + static std::string FormatLevel(ResourceType level) + { + switch (level) + { + case ResourceType_Patient: + return "patients"; + + case ResourceType_Study: + return "studies"; + + case ResourceType_Series: + return "series"; + + case ResourceType_Instance: + return "instances"; + + default: + throw OrthancException(ErrorCode_InternalError); + } + } + + + static bool FormatComparison(std::string& target, + ISqlLookupFormatter& formatter, + const DatabaseConstraint& constraint, + size_t index) + { + std::string tag = "t" + boost::lexical_cast(index); + + std::string comparison; + + switch (constraint.GetConstraintType()) + { + case ConstraintType_Equal: + case ConstraintType_SmallerOrEqual: + case ConstraintType_GreaterOrEqual: + { + std::string op; + switch (constraint.GetConstraintType()) + { + case ConstraintType_Equal: + op = "="; + break; + + case ConstraintType_SmallerOrEqual: + op = "<="; + break; + + case ConstraintType_GreaterOrEqual: + op = ">="; + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + + std::string parameter = formatter.GenerateParameter(constraint.GetSingleValue()); + + if (constraint.IsCaseSensitive()) + { + comparison = tag + ".value " + op + " " + parameter; + } + else + { + comparison = "lower(" + tag + ".value) " + op + " lower(" + parameter + ")"; + } + + break; + } + + case ConstraintType_List: + { + for (size_t i = 0; i < constraint.GetValuesCount(); i++) + { + if (!comparison.empty()) + { + comparison += ", "; + } + + std::string parameter = formatter.GenerateParameter(constraint.GetValue(i)); + + if (constraint.IsCaseSensitive()) + { + comparison += parameter; + } + else + { + comparison += "lower(" + parameter + ")"; + } + } + + if (constraint.IsCaseSensitive()) + { + comparison = tag + ".value IN (" + comparison + ")"; + } + else + { + comparison = "lower(" + tag + ".value) IN (" + comparison + ")"; + } + + break; + } + + case ConstraintType_Wildcard: + { + const std::string value = constraint.GetSingleValue(); + + if (value == "*") + { + if (!constraint.IsMandatory()) + { + // Universal constraint on an optional tag, ignore it + return false; + } + } + else + { + std::string escaped; + escaped.reserve(value.size()); + + for (size_t i = 0; i < value.size(); i++) + { + if (value[i] == '*') + { + escaped += "%"; + } + else if (value[i] == '?') + { + escaped += "_"; + } + else if (value[i] == '%') + { + escaped += "\\%"; + } + else if (value[i] == '_') + { + escaped += "\\_"; + } + else if (value[i] == '\\') + { + escaped += "\\\\"; + } + else + { + escaped += value[i]; + } + } + + std::string parameter = formatter.GenerateParameter(escaped); + + if (constraint.IsCaseSensitive()) + { + comparison = (tag + ".value LIKE " + parameter + " " + + formatter.FormatWildcardEscape()); + } + else + { + comparison = ("lower(" + tag + ".value) LIKE lower(" + + parameter + ") " + formatter.FormatWildcardEscape()); + } + } + + break; + } + + default: + return false; + } + + if (constraint.IsMandatory()) + { + target = comparison; + } + else if (comparison.empty()) + { + target = tag + ".value IS NULL"; + } + else + { + target = tag + ".value IS NULL OR " + comparison; + } + + return true; + } + + + static void FormatJoin(std::string& target, + const DatabaseConstraint& constraint, + size_t index) + { + std::string tag = "t" + boost::lexical_cast(index); + + if (constraint.IsMandatory()) + { + target = " INNER JOIN "; + } + else + { + target = " LEFT JOIN "; + } + + if (constraint.IsIdentifier()) + { + target += "DicomIdentifiers "; + } + else + { + target += "MainDicomTags "; + } + + target += (tag + " ON " + tag + ".id = " + FormatLevel(constraint.GetLevel()) + + ".internalId AND " + tag + ".tagGroup = " + + boost::lexical_cast(constraint.GetTag().GetGroup()) + + " AND " + tag + ".tagElement = " + + boost::lexical_cast(constraint.GetTag().GetElement())); + } + + + void ISqlLookupFormatter::Apply(std::string& sql, + ISqlLookupFormatter& formatter, + const std::vector& lookup, + ResourceType queryLevel, + size_t limit) + { + assert(ResourceType_Patient < ResourceType_Study && + ResourceType_Study < ResourceType_Series && + ResourceType_Series < ResourceType_Instance); + + ResourceType upperLevel = queryLevel; + ResourceType lowerLevel = queryLevel; + + for (size_t i = 0; i < lookup.size(); i++) + { + ResourceType level = lookup[i].GetLevel(); + + if (level < upperLevel) + { + upperLevel = level; + } + + if (level > lowerLevel) + { + lowerLevel = level; + } + } + + assert(upperLevel <= queryLevel && + queryLevel <= lowerLevel); + + std::string joins, comparisons; + + size_t count = 0; + + for (size_t i = 0; i < lookup.size(); i++) + { + std::string comparison; + + if (FormatComparison(comparison, formatter, lookup[i], count)) + { + std::string join; + FormatJoin(join, lookup[i], count); + joins += join; + + if (!comparison.empty()) + { + comparisons += " AND " + comparison; + } + + count ++; + } + } + + sql = ("SELECT " + + FormatLevel(queryLevel) + ".publicId, " + + FormatLevel(queryLevel) + ".internalId" + + " FROM Resources AS " + FormatLevel(queryLevel)); + + for (int level = queryLevel - 1; level >= upperLevel; level--) + { + sql += (" INNER JOIN Resources " + + FormatLevel(static_cast(level)) + " ON " + + FormatLevel(static_cast(level)) + ".internalId=" + + FormatLevel(static_cast(level + 1)) + ".parentId"); + } + + for (int level = queryLevel + 1; level <= lowerLevel; level++) + { + sql += (" INNER JOIN Resources " + + FormatLevel(static_cast(level)) + " ON " + + FormatLevel(static_cast(level - 1)) + ".internalId=" + + FormatLevel(static_cast(level)) + ".parentId"); + } + + sql += (joins + " WHERE " + FormatLevel(queryLevel) + ".resourceType = " + + formatter.FormatResourceType(queryLevel) + comparisons); + + if (limit != 0) + { + sql += " LIMIT " + boost::lexical_cast(limit); + } + } +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Databases/ISqlLookupFormatter.h orthanc-mysql-3.0/Resources/Orthanc/Databases/ISqlLookupFormatter.h --- orthanc-mysql-2.0/Resources/Orthanc/Databases/ISqlLookupFormatter.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Databases/ISqlLookupFormatter.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,69 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#if ORTHANC_BUILDING_SERVER_LIBRARY == 1 +# include "../../../OrthancFramework/Sources/Enumerations.h" +#else +# include +#endif + +#include +#include + +namespace Orthanc +{ + class DatabaseConstraint; + + // This class is also used by the "orthanc-databases" project + class ISqlLookupFormatter : public boost::noncopyable + { + public: + virtual ~ISqlLookupFormatter() + { + } + + virtual std::string GenerateParameter(const std::string& value) = 0; + + virtual std::string FormatResourceType(ResourceType level) = 0; + + virtual std::string FormatWildcardEscape() = 0; + + static void Apply(std::string& sql, + ISqlLookupFormatter& formatter, + const std::vector& lookup, + ResourceType queryLevel, + size_t limit); + }; +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/DownloadOrthancFramework.cmake orthanc-mysql-3.0/Resources/Orthanc/DownloadOrthancFramework.cmake --- orthanc-mysql-2.0/Resources/Orthanc/DownloadOrthancFramework.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/DownloadOrthancFramework.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,334 +0,0 @@ -# Orthanc - A Lightweight, RESTful DICOM Store -# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics -# Department, University Hospital of Liege, Belgium -# Copyright (C) 2017-2019 Osimis S.A., Belgium -# -# This program is free software: you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# In addition, as a special exception, the copyright holders of this -# program give permission to link the code of its release with the -# OpenSSL project's "OpenSSL" library (or with modified versions of it -# that use the same license as the "OpenSSL" library), and distribute -# the linked executables. You must obey the GNU General Public License -# in all respects for all of the code used other than "OpenSSL". If you -# modify file(s) with this exception, you may extend this exception to -# your version of the file(s), but you are not obligated to do so. If -# you do not wish to do so, delete this exception statement from your -# version. If you delete this exception statement from all source files -# in the program, then also delete it here. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - - -## -## Check whether the parent script sets the mandatory variables -## - -if (NOT DEFINED ORTHANC_FRAMEWORK_SOURCE OR - (NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" AND - NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "web" AND - NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" AND - NOT ORTHANC_FRAMEWORK_SOURCE STREQUAL "path")) - message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_SOURCE must be set to \"hg\", \"web\", \"archive\" or \"path\"") -endif() - - -## -## Detection of the requested version -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" OR - ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR - ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") - if (NOT DEFINED ORTHANC_FRAMEWORK_VERSION) - message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_VERSION must be set") - endif() - - if (DEFINED ORTHANC_FRAMEWORK_MAJOR OR - DEFINED ORTHANC_FRAMEWORK_MINOR OR - DEFINED ORTHANC_FRAMEWORK_REVISION OR - DEFINED ORTHANC_FRAMEWORK_MD5) - message(FATAL_ERROR "Some internal variable has been set") - endif() - - set(ORTHANC_FRAMEWORK_MD5 "") - - if (NOT DEFINED ORTHANC_FRAMEWORK_BRANCH) - if (ORTHANC_FRAMEWORK_VERSION STREQUAL "mainline") - set(ORTHANC_FRAMEWORK_BRANCH "default") - - else() - set(ORTHANC_FRAMEWORK_BRANCH "Orthanc-${ORTHANC_FRAMEWORK_VERSION}") - - set(RE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$") - string(REGEX REPLACE ${RE} "\\1" ORTHANC_FRAMEWORK_MAJOR ${ORTHANC_FRAMEWORK_VERSION}) - string(REGEX REPLACE ${RE} "\\2" ORTHANC_FRAMEWORK_MINOR ${ORTHANC_FRAMEWORK_VERSION}) - string(REGEX REPLACE ${RE} "\\3" ORTHANC_FRAMEWORK_REVISION ${ORTHANC_FRAMEWORK_VERSION}) - - if (NOT ORTHANC_FRAMEWORK_MAJOR MATCHES "^[0-9]+$" OR - NOT ORTHANC_FRAMEWORK_MINOR MATCHES "^[0-9]+$" OR - NOT ORTHANC_FRAMEWORK_REVISION MATCHES "^[0-9]+$") - message("Bad version of the Orthanc framework: ${ORTHANC_FRAMEWORK_VERSION}") - endif() - - if (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.1") - set(ORTHANC_FRAMEWORK_MD5 "dac95bd6cf86fb19deaf4e612961f378") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.3.2") - set(ORTHANC_FRAMEWORK_MD5 "d0ccdf68e855d8224331f13774992750") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.0") - set(ORTHANC_FRAMEWORK_MD5 "81e15f34d97ac32bbd7d26e85698835a") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.1") - set(ORTHANC_FRAMEWORK_MD5 "9b6f6114264b17ed421b574cd6476127") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.4.2") - set(ORTHANC_FRAMEWORK_MD5 "d1ee84927dcf668e60eb5868d24b9394") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.0") - set(ORTHANC_FRAMEWORK_MD5 "4429d8d9dea4ff6648df80ec3c64d79e") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.1") - set(ORTHANC_FRAMEWORK_MD5 "099671538865e5da96208b37494d6718") - elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.2") - set(ORTHANC_FRAMEWORK_MD5 "8867050f3e9a1ce6157c1ea7a9433b1b") - endif() - endif() - endif() -endif() - - - -## -## Detection of the third-party software -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg") - find_program(ORTHANC_FRAMEWORK_HG hg) - - if (${ORTHANC_FRAMEWORK_HG} MATCHES "ORTHANC_FRAMEWORK_HG-NOTFOUND") - message(FATAL_ERROR "Please install Mercurial") - endif() -endif() - - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR - ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") - if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - find_program(ORTHANC_FRAMEWORK_7ZIP 7z - PATHS - "$ENV{ProgramFiles}/7-Zip" - "$ENV{ProgramW6432}/7-Zip" - ) - - if (${ORTHANC_FRAMEWORK_7ZIP} MATCHES "ORTHANC_FRAMEWORK_7ZIP-NOTFOUND") - message(FATAL_ERROR "Please install the '7-zip' software (http://www.7-zip.org/)") - endif() - - else() - find_program(ORTHANC_FRAMEWORK_TAR tar) - if (${ORTHANC_FRAMEWORK_TAR} MATCHES "ORTHANC_FRAMEWORK_TAR-NOTFOUND") - message(FATAL_ERROR "Please install the 'tar' package") - endif() - endif() -endif() - - - -## -## Case of the Orthanc framework specified as a path on the filesystem -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "path") - if (NOT DEFINED ORTHANC_FRAMEWORK_ROOT) - message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_ROOT must provide the path to the sources of Orthanc") - endif() - - if (NOT EXISTS ${ORTHANC_FRAMEWORK_ROOT}) - message(FATAL_ERROR "Non-existing directory: ${ORTHANC_FRAMEWORK_ROOT}") - endif() - - if (NOT EXISTS ${ORTHANC_FRAMEWORK_ROOT}/Resources/CMake/OrthancFrameworkParameters.cmake) - message(FATAL_ERROR "Directory not containing the source code of Orthanc: ${ORTHANC_FRAMEWORK_ROOT}") - endif() - - set(ORTHANC_ROOT ${ORTHANC_FRAMEWORK_ROOT}) -endif() - - - -## -## Case of the Orthanc framework cloned using Mercurial -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg") - if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) - message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") - endif() - - set(ORTHANC_ROOT ${CMAKE_BINARY_DIR}/orthanc) - - if (EXISTS ${ORTHANC_ROOT}) - message("Updating the Orthanc source repository using Mercurial") - execute_process( - COMMAND ${ORTHANC_FRAMEWORK_HG} pull - WORKING_DIRECTORY ${ORTHANC_ROOT} - RESULT_VARIABLE Failure - ) - else() - message("Forking the Orthanc source repository using Mercurial") - execute_process( - COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://bitbucket.org/sjodogne/orthanc" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - endif() - - if (Failure OR NOT EXISTS ${ORTHANC_ROOT}) - message(FATAL_ERROR "Cannot fork the Orthanc repository") - endif() - - message("Setting branch of the Orthanc repository to: ${ORTHANC_FRAMEWORK_BRANCH}") - - execute_process( - COMMAND ${ORTHANC_FRAMEWORK_HG} update -c ${ORTHANC_FRAMEWORK_BRANCH} - WORKING_DIRECTORY ${ORTHANC_ROOT} - RESULT_VARIABLE Failure - ) - - if (Failure) - message(FATAL_ERROR "Error while running Mercurial") - endif() -endif() - - - -## -## Case of the Orthanc framework provided as a source archive on the -## filesystem -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive") - if (NOT DEFINED ORTHANC_FRAMEWORK_ARCHIVE) - message(FATAL_ERROR "The variable ORTHANC_FRAMEWORK_ARCHIVE must provide the path to the sources of Orthanc") - endif() -endif() - - - -## -## Case of the Orthanc framework downloaded from the Web -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") - if (DEFINED ORTHANC_FRAMEWORK_URL) - string(REGEX REPLACE "^.*/" "" ORTHANC_FRAMEMORK_FILENAME "${ORTHANC_FRAMEWORK_URL}") - else() - # Default case: Download from the official Web site - set(ORTHANC_FRAMEMORK_FILENAME Orthanc-${ORTHANC_FRAMEWORK_VERSION}.tar.gz) - set(ORTHANC_FRAMEWORK_URL "http://orthanc.osimis.io/ThirdPartyDownloads/orthanc-framework/${ORTHANC_FRAMEMORK_FILENAME}") - endif() - - set(ORTHANC_FRAMEWORK_ARCHIVE "${CMAKE_SOURCE_DIR}/ThirdPartyDownloads/${ORTHANC_FRAMEMORK_FILENAME}") - - if (NOT EXISTS "${ORTHANC_FRAMEWORK_ARCHIVE}") - if (NOT STATIC_BUILD AND NOT ALLOW_DOWNLOADS) - message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON") - endif() - - message("Downloading: ${ORTHANC_FRAMEWORK_URL}") - - file(DOWNLOAD - "${ORTHANC_FRAMEWORK_URL}" "${ORTHANC_FRAMEWORK_ARCHIVE}" - SHOW_PROGRESS EXPECTED_MD5 "${ORTHANC_FRAMEWORK_MD5}" - TIMEOUT 60 - INACTIVITY_TIMEOUT 60 - ) - else() - message("Using local copy of: ${ORTHANC_FRAMEWORK_URL}") - endif() -endif() - - - - -## -## Uncompressing the Orthanc framework, if it was retrieved from a -## source archive on the filesystem, or from the official Web site -## - -if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "archive" OR - ORTHANC_FRAMEWORK_SOURCE STREQUAL "web") - - if (NOT DEFINED ORTHANC_FRAMEWORK_ARCHIVE OR - NOT DEFINED ORTHANC_FRAMEWORK_VERSION OR - NOT DEFINED ORTHANC_FRAMEWORK_MD5) - message(FATAL_ERROR "Internal error") - endif() - - if (ORTHANC_FRAMEWORK_MD5 STREQUAL "") - message(FATAL_ERROR "Unknown release of Orthanc: ${ORTHANC_FRAMEWORK_VERSION}") - endif() - - file(MD5 ${ORTHANC_FRAMEWORK_ARCHIVE} ActualMD5) - - if (NOT "${ActualMD5}" STREQUAL "${ORTHANC_FRAMEWORK_MD5}") - message(FATAL_ERROR "The MD5 hash of the Orthanc archive is invalid: ${ORTHANC_FRAMEWORK_ARCHIVE}") - endif() - - set(ORTHANC_ROOT "${CMAKE_BINARY_DIR}/Orthanc-${ORTHANC_FRAMEWORK_VERSION}") - - if (NOT IS_DIRECTORY "${ORTHANC_ROOT}") - if (NOT ORTHANC_FRAMEWORK_ARCHIVE MATCHES ".tar.gz$") - message(FATAL_ERROR "Archive should have the \".tar.gz\" extension: ${ORTHANC_FRAMEWORK_ARCHIVE}") - endif() - - message("Uncompressing: ${ORTHANC_FRAMEWORK_ARCHIVE}") - - if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows") - # How to silently extract files using 7-zip - # http://superuser.com/questions/331148/7zip-command-line-extract-silently-quietly - - execute_process( - COMMAND ${ORTHANC_FRAMEWORK_7ZIP} e -y ${ORTHANC_FRAMEWORK_ARCHIVE} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - get_filename_component(TMP_FILENAME "${ORTHANC_FRAMEWORK_ARCHIVE}" NAME) - string(REGEX REPLACE ".gz$" "" TMP_FILENAME2 "${TMP_FILENAME}") - - execute_process( - COMMAND ${ORTHANC_FRAMEWORK_7ZIP} x -y ${TMP_FILENAME2} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - OUTPUT_QUIET - ) - - else() - execute_process( - COMMAND sh -c "${ORTHANC_FRAMEWORK_TAR} xfz ${ORTHANC_FRAMEWORK_ARCHIVE}" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - RESULT_VARIABLE Failure - ) - endif() - - if (Failure) - message(FATAL_ERROR "Error while running the uncompression tool") - endif() - - if (NOT IS_DIRECTORY "${ORTHANC_ROOT}") - message(FATAL_ERROR "The Orthanc framework was not uncompressed at the proper location. Check the CMake instructions.") - endif() - endif() -endif() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/EmbedResources.py orthanc-mysql-3.0/Resources/Orthanc/EmbedResources.py --- orthanc-mysql-2.0/Resources/Orthanc/EmbedResources.py 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/EmbedResources.py 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,444 @@ +#!/usr/bin/python + +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +import sys +import os +import os.path +import pprint +import re + +UPCASE_CHECK = True +USE_SYSTEM_EXCEPTION = False +EXCEPTION_CLASS = 'OrthancException' +OUT_OF_RANGE_EXCEPTION = '::Orthanc::OrthancException(::Orthanc::ErrorCode_ParameterOutOfRange)' +INEXISTENT_PATH_EXCEPTION = '::Orthanc::OrthancException(::Orthanc::ErrorCode_InexistentItem)' +NAMESPACE = 'Orthanc.EmbeddedResources' +FRAMEWORK_PATH = None + +ARGS = [] +for i in range(len(sys.argv)): + if not sys.argv[i].startswith('--'): + ARGS.append(sys.argv[i]) + elif sys.argv[i].lower() == '--no-upcase-check': + UPCASE_CHECK = False + elif sys.argv[i].lower() == '--system-exception': + USE_SYSTEM_EXCEPTION = True + EXCEPTION_CLASS = '::std::runtime_error' + OUT_OF_RANGE_EXCEPTION = '%s("Parameter out of range")' % EXCEPTION_CLASS + INEXISTENT_PATH_EXCEPTION = '%s("Unknown path in a directory resource")' % EXCEPTION_CLASS + elif sys.argv[i].startswith('--namespace='): + NAMESPACE = sys.argv[i][sys.argv[i].find('=') + 1 : ] + elif sys.argv[i].startswith('--framework-path='): + FRAMEWORK_PATH = sys.argv[i][sys.argv[i].find('=') + 1 : ] + +if len(ARGS) < 2 or len(ARGS) % 2 != 0: + print ('Usage:') + print ('python %s [--no-upcase-check] [--system-exception] [--namespace=] [ ]*' % sys.argv[0]) + exit(-1) + +TARGET_BASE_FILENAME = ARGS[1] +SOURCES = ARGS[2:] + +try: + # Make sure the destination directory exists + os.makedirs(os.path.normpath(os.path.join(TARGET_BASE_FILENAME, '..'))) +except: + pass + + +##################################################################### +## Read each resource file +##################################################################### + +def CheckNoUpcase(s): + global UPCASE_CHECK + if (UPCASE_CHECK and + re.search('[A-Z]', s) != None): + raise Exception("Path in a directory with an upcase letter: %s" % s) + +resources = {} + +counter = 0 +i = 0 +while i < len(SOURCES): + resourceName = SOURCES[i].upper() + pathName = SOURCES[i + 1] + + if not os.path.exists(pathName): + raise Exception("Non existing path: %s" % pathName) + + if resourceName in resources: + raise Exception("Twice the same resource: " + resourceName) + + if os.path.isdir(pathName): + # The resource is a directory: Recursively explore its files + content = {} + for root, dirs, files in os.walk(pathName): + dirs.sort() + files.sort() + base = os.path.relpath(root, pathName) + + # Fix issue #24 (Build fails on OSX when directory has .DS_Store files): + # Ignore folders whose name starts with a dot (".") + if base.find('/.') != -1: + print('Ignoring folder: %s' % root) + continue + + for f in files: + if f.find('~') == -1: # Ignore Emacs backup files + if base == '.': + r = f + else: + r = os.path.join(base, f) + + CheckNoUpcase(r) + r = '/' + r.replace('\\', '/') + if r in content: + raise Exception("Twice the same filename (check case): " + r) + + content[r] = { + 'Filename' : os.path.join(root, f), + 'Index' : counter + } + counter += 1 + + resources[resourceName] = { + 'Type' : 'Directory', + 'Files' : content + } + + elif os.path.isfile(pathName): + resources[resourceName] = { + 'Type' : 'File', + 'Index' : counter, + 'Filename' : pathName + } + counter += 1 + + else: + raise Exception("Not a regular file, nor a directory: " + pathName) + + i += 2 + +#pprint.pprint(resources) + + +##################################################################### +## Write .h header +##################################################################### + +header = open(TARGET_BASE_FILENAME + '.h', 'w') + +header.write(""" +#pragma once + +#include +#include + +#if defined(_MSC_VER) +# pragma warning(disable: 4065) // "Switch statement contains 'default' but no 'case' labels" +#endif + +""") + + +for ns in NAMESPACE.split('.'): + header.write('namespace %s {\n' % ns) + + +header.write(""" + enum FileResourceId + { +""") + +isFirst = True +for name in resources: + if resources[name]['Type'] == 'File': + if isFirst: + isFirst = False + else: + header.write(',\n') + header.write(' %s' % name) + +header.write(""" + }; + + enum DirectoryResourceId + { +""") + +isFirst = True +for name in resources: + if resources[name]['Type'] == 'Directory': + if isFirst: + isFirst = False + else: + header.write(',\n') + header.write(' %s' % name) + +header.write(""" + }; + + const void* GetFileResourceBuffer(FileResourceId id); + size_t GetFileResourceSize(FileResourceId id); + void GetFileResource(std::string& result, FileResourceId id); + + const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path); + size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path); + void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path); + + void ListResources(std::list& result, DirectoryResourceId id); + +""") + + +for ns in NAMESPACE.split('.'): + header.write('}\n') + +header.close() + + + +##################################################################### +## Write the resource content in the .cpp source +##################################################################### + +PYTHON_MAJOR_VERSION = sys.version_info[0] + +def WriteResource(cpp, item): + cpp.write(' static const uint8_t resource%dBuffer[] = {' % item['Index']) + + f = open(item['Filename'], "rb") + content = f.read() + f.close() + + # http://stackoverflow.com/a/1035360 + pos = 0 + buffer = [] # instead of appending a few bytes at a time to the cpp file, + # we first append each chunk to a list, join it and write it + # to the file. We've measured that it was 2-3 times faster in python3. + # Note that speed is important since if generation is too slow, + # cmake might try to compile the EmbeddedResources.cpp file while it is + # still being generated ! + for b in content: + if PYTHON_MAJOR_VERSION == 2: + c = ord(b[0]) + else: + c = b + + if pos > 0: + buffer.append(",") + + if (pos % 16) == 0: + buffer.append("\n") + + if c < 0: + raise Exception("Internal error") + + buffer.append("0x%02x" % c) + pos += 1 + + cpp.write("".join(buffer)) + # Zero-size array are disallowed, so we put one single void character in it. + if pos == 0: + cpp.write(' 0') + + cpp.write(' };\n') + cpp.write(' static const size_t resource%dSize = %d;\n' % (item['Index'], pos)) + + +cpp = open(TARGET_BASE_FILENAME + '.cpp', 'w') + +cpp.write('#include "%s.h"\n' % os.path.basename(TARGET_BASE_FILENAME)) + +if USE_SYSTEM_EXCEPTION: + cpp.write('#include ') +elif FRAMEWORK_PATH != None: + cpp.write('#include "%s/OrthancException.h"' % FRAMEWORK_PATH) +else: + cpp.write('#include ') + +cpp.write(""" +#include +#include + +""") + +for ns in NAMESPACE.split('.'): + cpp.write('namespace %s {\n' % ns) + + +for name in resources: + if resources[name]['Type'] == 'File': + WriteResource(cpp, resources[name]) + else: + for f in resources[name]['Files']: + WriteResource(cpp, resources[name]['Files'][f]) + + + +##################################################################### +## Write the accessors to the file resources in .cpp +##################################################################### + +cpp.write(""" + const void* GetFileResourceBuffer(FileResourceId id) + { + switch (id) + { +""") +for name in resources: + if resources[name]['Type'] == 'File': + cpp.write(' case %s:\n' % name) + cpp.write(' return resource%dBuffer;\n' % resources[name]['Index']) + +cpp.write(""" + default: + throw %s; + } + } + + size_t GetFileResourceSize(FileResourceId id) + { + switch (id) + { +""" % OUT_OF_RANGE_EXCEPTION) + +for name in resources: + if resources[name]['Type'] == 'File': + cpp.write(' case %s:\n' % name) + cpp.write(' return resource%dSize;\n' % resources[name]['Index']) + +cpp.write(""" + default: + throw %s; + } + } +""" % OUT_OF_RANGE_EXCEPTION) + + + +##################################################################### +## Write the accessors to the directory resources in .cpp +##################################################################### + +cpp.write(""" + const void* GetDirectoryResourceBuffer(DirectoryResourceId id, const char* path) + { + switch (id) + { +""") + +for name in resources: + if resources[name]['Type'] == 'Directory': + cpp.write(' case %s:\n' % name) + isFirst = True + for path in resources[name]['Files']: + cpp.write(' if (!strcmp(path, "%s"))\n' % path) + cpp.write(' return resource%dBuffer;\n' % resources[name]['Files'][path]['Index']) + cpp.write(' throw %s;\n\n' % INEXISTENT_PATH_EXCEPTION) + +cpp.write(""" default: + throw %s; + } + } + + size_t GetDirectoryResourceSize(DirectoryResourceId id, const char* path) + { + switch (id) + { +""" % OUT_OF_RANGE_EXCEPTION) + +for name in resources: + if resources[name]['Type'] == 'Directory': + cpp.write(' case %s:\n' % name) + isFirst = True + for path in resources[name]['Files']: + cpp.write(' if (!strcmp(path, "%s"))\n' % path) + cpp.write(' return resource%dSize;\n' % resources[name]['Files'][path]['Index']) + cpp.write(' throw %s;\n\n' % INEXISTENT_PATH_EXCEPTION) + +cpp.write(""" default: + throw %s; + } + } +""" % OUT_OF_RANGE_EXCEPTION) + + + + +##################################################################### +## List the resources in a directory +##################################################################### + +cpp.write(""" + void ListResources(std::list& result, DirectoryResourceId id) + { + result.clear(); + + switch (id) + { +""") + +for name in resources: + if resources[name]['Type'] == 'Directory': + cpp.write(' case %s:\n' % name) + for path in sorted(resources[name]['Files']): + cpp.write(' result.push_back("%s");\n' % path) + cpp.write(' break;\n\n') + +cpp.write(""" default: + throw %s; + } + } +""" % OUT_OF_RANGE_EXCEPTION) + + + + +##################################################################### +## Write the convenience wrappers in .cpp +##################################################################### + +cpp.write(""" + void GetFileResource(std::string& result, FileResourceId id) + { + size_t size = GetFileResourceSize(id); + result.resize(size); + if (size > 0) + memcpy(&result[0], GetFileResourceBuffer(id), size); + } + + void GetDirectoryResource(std::string& result, DirectoryResourceId id, const char* path) + { + size_t size = GetDirectoryResourceSize(id, path); + result.resize(size); + if (size > 0) + memcpy(&result[0], GetDirectoryResourceBuffer(id, path), size); + } +""") + + +for ns in NAMESPACE.split('.'): + cpp.write('}\n') + +cpp.close() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/LinuxStandardBaseToolchain.cmake orthanc-mysql-3.0/Resources/Orthanc/LinuxStandardBaseToolchain.cmake --- orthanc-mysql-2.0/Resources/Orthanc/LinuxStandardBaseToolchain.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/LinuxStandardBaseToolchain.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,11 +1,39 @@ -# LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../Resources/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + +# +# Full build, as used on the BuildBot CIS: +# +# $ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake ../OrthancServer/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON -DUSE_LEGACY_LIBICU=ON -DBOOST_LOCALE_BACKEND=icu -DENABLE_PKCS11=ON -G Ninja +# +# Or, more lightweight version (without libp11 and ICU): +# +# $ LSB_CC=gcc-4.8 LSB_CXX=g++-4.8 cmake ../OrthancServer/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=../OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake -DUSE_LEGACY_JSONCPP=ON -G Ninja +# INCLUDE(CMakeForceCompiler) -SET(LSB_PATH $ENV{LSB_PATH}) -SET(LSB_CC $ENV{LSB_CC}) -SET(LSB_CXX $ENV{LSB_CXX}) -SET(LSB_TARGET_VERSION "4.0") +SET(LSB_PATH $ENV{LSB_PATH} CACHE STRING "") +SET(LSB_CC $ENV{LSB_CC} CACHE STRING "") +SET(LSB_CXX $ENV{LSB_CXX} CACHE STRING "") +SET(LSB_TARGET_VERSION "4.0" CACHE STRING "") IF ("${LSB_PATH}" STREQUAL "") SET(LSB_PATH "/opt/lsb") @@ -31,7 +59,12 @@ # which compilers to use for C and C++ SET(CMAKE_C_COMPILER ${LSB_PATH}/bin/lsbcc) -CMAKE_FORCE_CXX_COMPILER(${LSB_PATH}/bin/lsbc++ GNU) + +if (${CMAKE_VERSION} VERSION_LESS "3.6.0") + CMAKE_FORCE_CXX_COMPILER(${LSB_PATH}/bin/lsbc++ GNU) +else() + SET(CMAKE_CXX_COMPILER ${LSB_PATH}/bin/lsbc++) +endif() # here is the target environment located SET(CMAKE_FIND_ROOT_PATH ${LSB_PATH}) diff -Nru orthanc-mysql-2.0/Resources/Orthanc/MinGWToolchain.cmake orthanc-mysql-3.0/Resources/Orthanc/MinGWToolchain.cmake --- orthanc-mysql-2.0/Resources/Orthanc/MinGWToolchain.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/MinGWToolchain.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,3 +1,23 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + # the name of the target operating system set(CMAKE_SYSTEM_NAME Windows) diff -Nru orthanc-mysql-2.0/Resources/Orthanc/MinGW-W64-Toolchain32.cmake orthanc-mysql-3.0/Resources/Orthanc/MinGW-W64-Toolchain32.cmake --- orthanc-mysql-2.0/Resources/Orthanc/MinGW-W64-Toolchain32.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/MinGW-W64-Toolchain32.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,3 +1,23 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + # the name of the target operating system set(CMAKE_SYSTEM_NAME Windows) diff -Nru orthanc-mysql-2.0/Resources/Orthanc/MinGW-W64-Toolchain64.cmake orthanc-mysql-3.0/Resources/Orthanc/MinGW-W64-Toolchain64.cmake --- orthanc-mysql-2.0/Resources/Orthanc/MinGW-W64-Toolchain64.cmake 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/MinGW-W64-Toolchain64.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -1,3 +1,23 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program. If not, see +# . + + # the name of the target operating system set(CMAKE_SYSTEM_NAME Windows) diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Plugins/ExportedSymbolsPlugins.list orthanc-mysql-3.0/Resources/Orthanc/Plugins/ExportedSymbolsPlugins.list --- orthanc-mysql-2.0/Resources/Orthanc/Plugins/ExportedSymbolsPlugins.list 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Plugins/ExportedSymbolsPlugins.list 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,7 @@ +# This is the list of the symbols that must be exported by Orthanc +# plugins, if targeting OS X + +_OrthancPluginInitialize +_OrthancPluginFinalize +_OrthancPluginGetName +_OrthancPluginGetVersion diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp --- orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,3383 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "OrthancPluginCppWrapper.h" + +#include +#include +#include +#include +#include + + +#if !ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0) +static const OrthancPluginErrorCode OrthancPluginErrorCode_NullPointer = OrthancPluginErrorCode_Plugin; +#endif + + +namespace OrthancPlugins +{ + static OrthancPluginContext* globalContext_ = NULL; + + + void SetGlobalContext(OrthancPluginContext* context) + { + if (context == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(NullPointer); + } + else if (globalContext_ == NULL) + { + globalContext_ = context; + } + else + { + ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); + } + } + + + bool HasGlobalContext() + { + return globalContext_ != NULL; + } + + + OrthancPluginContext* GetGlobalContext() + { + if (globalContext_ == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(BadSequenceOfCalls); + } + else + { + return globalContext_; + } + } + + + void MemoryBuffer::Check(OrthancPluginErrorCode code) + { + if (code != OrthancPluginErrorCode_Success) + { + // Prevent using garbage information + buffer_.data = NULL; + buffer_.size = 0; + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); + } + } + + + bool MemoryBuffer::CheckHttp(OrthancPluginErrorCode code) + { + if (code != OrthancPluginErrorCode_Success) + { + // Prevent using garbage information + buffer_.data = NULL; + buffer_.size = 0; + } + + if (code == OrthancPluginErrorCode_Success) + { + return true; + } + else if (code == OrthancPluginErrorCode_UnknownResource || + code == OrthancPluginErrorCode_InexistentItem) + { + return false; + } + else + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); + } + } + + + MemoryBuffer::MemoryBuffer() + { + buffer_.data = NULL; + buffer_.size = 0; + } + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + MemoryBuffer::MemoryBuffer(const void* buffer, + size_t size) + { + uint32_t s = static_cast(size); + if (static_cast(s) != size) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory); + } + else if (OrthancPluginCreateMemoryBuffer(GetGlobalContext(), &buffer_, s) != + OrthancPluginErrorCode_Success) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory); + } + else + { + memcpy(buffer_.data, buffer, size); + } + } +#endif + + + void MemoryBuffer::Clear() + { + if (buffer_.data != NULL) + { + OrthancPluginFreeMemoryBuffer(GetGlobalContext(), &buffer_); + buffer_.data = NULL; + buffer_.size = 0; + } + } + + + void MemoryBuffer::Assign(OrthancPluginMemoryBuffer& other) + { + Clear(); + + buffer_.data = other.data; + buffer_.size = other.size; + + other.data = NULL; + other.size = 0; + } + + + void MemoryBuffer::Swap(MemoryBuffer& other) + { + std::swap(buffer_.data, other.buffer_.data); + std::swap(buffer_.size, other.buffer_.size); + } + + + OrthancPluginMemoryBuffer MemoryBuffer::Release() + { + OrthancPluginMemoryBuffer result = buffer_; + + buffer_.data = NULL; + buffer_.size = 0; + + return result; + } + + + void MemoryBuffer::ToString(std::string& target) const + { + if (buffer_.size == 0) + { + target.clear(); + } + else + { + target.assign(reinterpret_cast(buffer_.data), buffer_.size); + } + } + + + void MemoryBuffer::ToJson(Json::Value& target) const + { + if (buffer_.data == NULL || + buffer_.size == 0) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + const char* tmp = reinterpret_cast(buffer_.data); + + Json::Reader reader; + if (!reader.parse(tmp, tmp + buffer_.size, target)) + { + LogError("Cannot convert some memory buffer to JSON"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + } + + + bool MemoryBuffer::RestApiGet(const std::string& uri, + bool applyPlugins) + { + Clear(); + + if (applyPlugins) + { + return CheckHttp(OrthancPluginRestApiGetAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str())); + } + else + { + return CheckHttp(OrthancPluginRestApiGet(GetGlobalContext(), &buffer_, uri.c_str())); + } + } + + bool MemoryBuffer::RestApiGet(const std::string& uri, + const std::map& httpHeaders, + bool applyPlugins) + { + Clear(); + + std::vector headersKeys; + std::vector headersValues; + + for (std::map::const_iterator + it = httpHeaders.begin(); it != httpHeaders.end(); it++) + { + headersKeys.push_back(it->first.c_str()); + headersValues.push_back(it->second.c_str()); + } + + return CheckHttp(OrthancPluginRestApiGet2( + GetGlobalContext(), &buffer_, uri.c_str(), httpHeaders.size(), + (headersKeys.empty() ? NULL : &headersKeys[0]), + (headersValues.empty() ? NULL : &headersValues[0]), applyPlugins)); + } + + bool MemoryBuffer::RestApiPost(const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins) + { + Clear(); + + // Cast for compatibility with Orthanc SDK <= 1.5.6 + const char* b = reinterpret_cast(body); + + if (applyPlugins) + { + return CheckHttp(OrthancPluginRestApiPostAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); + } + else + { + return CheckHttp(OrthancPluginRestApiPost(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); + } + } + + + bool MemoryBuffer::RestApiPut(const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins) + { + Clear(); + + // Cast for compatibility with Orthanc SDK <= 1.5.6 + const char* b = reinterpret_cast(body); + + if (applyPlugins) + { + return CheckHttp(OrthancPluginRestApiPutAfterPlugins(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); + } + else + { + return CheckHttp(OrthancPluginRestApiPut(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); + } + } + + + bool MemoryBuffer::RestApiPost(const std::string& uri, + const Json::Value& body, + bool applyPlugins) + { + Json::FastWriter writer; + return RestApiPost(uri, writer.write(body), applyPlugins); + } + + + bool MemoryBuffer::RestApiPut(const std::string& uri, + const Json::Value& body, + bool applyPlugins) + { + Json::FastWriter writer; + return RestApiPut(uri, writer.write(body), applyPlugins); + } + + + void MemoryBuffer::CreateDicom(const Json::Value& tags, + OrthancPluginCreateDicomFlags flags) + { + Clear(); + + Json::FastWriter writer; + std::string s = writer.write(tags); + + Check(OrthancPluginCreateDicom(GetGlobalContext(), &buffer_, s.c_str(), NULL, flags)); + } + + void MemoryBuffer::CreateDicom(const Json::Value& tags, + const OrthancImage& pixelData, + OrthancPluginCreateDicomFlags flags) + { + Clear(); + + Json::FastWriter writer; + std::string s = writer.write(tags); + + Check(OrthancPluginCreateDicom(GetGlobalContext(), &buffer_, s.c_str(), pixelData.GetObject(), flags)); + } + + + void MemoryBuffer::ReadFile(const std::string& path) + { + Clear(); + Check(OrthancPluginReadFile(GetGlobalContext(), &buffer_, path.c_str())); + } + + + void MemoryBuffer::GetDicomQuery(const OrthancPluginWorklistQuery* query) + { + Clear(); + Check(OrthancPluginWorklistGetDicomQuery(GetGlobalContext(), &buffer_, query)); + } + + + void OrthancString::Assign(char* str) + { + Clear(); + + if (str != NULL) + { + str_ = str; + } + } + + + void OrthancString::Clear() + { + if (str_ != NULL) + { + OrthancPluginFreeString(GetGlobalContext(), str_); + str_ = NULL; + } + } + + + void OrthancString::ToString(std::string& target) const + { + if (str_ == NULL) + { + target.clear(); + } + else + { + target.assign(str_); + } + } + + + void OrthancString::ToJson(Json::Value& target) const + { + if (str_ == NULL) + { + LogError("Cannot convert an empty memory buffer to JSON"); + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + Json::Reader reader; + if (!reader.parse(str_, target)) + { + LogError("Cannot convert some memory buffer to JSON"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + } + + + void MemoryBuffer::DicomToJson(Json::Value& target, + OrthancPluginDicomToJsonFormat format, + OrthancPluginDicomToJsonFlags flags, + uint32_t maxStringLength) + { + OrthancString str; + str.Assign(OrthancPluginDicomBufferToJson + (GetGlobalContext(), GetData(), GetSize(), format, flags, maxStringLength)); + str.ToJson(target); + } + + + bool MemoryBuffer::HttpGet(const std::string& url, + const std::string& username, + const std::string& password) + { + Clear(); + return CheckHttp(OrthancPluginHttpGet(GetGlobalContext(), &buffer_, url.c_str(), + username.empty() ? NULL : username.c_str(), + password.empty() ? NULL : password.c_str())); + } + + + bool MemoryBuffer::HttpPost(const std::string& url, + const std::string& body, + const std::string& username, + const std::string& password) + { + Clear(); + return CheckHttp(OrthancPluginHttpPost(GetGlobalContext(), &buffer_, url.c_str(), + body.c_str(), body.size(), + username.empty() ? NULL : username.c_str(), + password.empty() ? NULL : password.c_str())); + } + + + bool MemoryBuffer::HttpPut(const std::string& url, + const std::string& body, + const std::string& username, + const std::string& password) + { + Clear(); + return CheckHttp(OrthancPluginHttpPut(GetGlobalContext(), &buffer_, url.c_str(), + body.empty() ? NULL : body.c_str(), + body.size(), + username.empty() ? NULL : username.c_str(), + password.empty() ? NULL : password.c_str())); + } + + + void MemoryBuffer::GetDicomInstance(const std::string& instanceId) + { + Clear(); + Check(OrthancPluginGetDicomForInstance(GetGlobalContext(), &buffer_, instanceId.c_str())); + } + + + bool HttpDelete(const std::string& url, + const std::string& username, + const std::string& password) + { + OrthancPluginErrorCode error = OrthancPluginHttpDelete + (GetGlobalContext(), url.c_str(), + username.empty() ? NULL : username.c_str(), + password.empty() ? NULL : password.c_str()); + + if (error == OrthancPluginErrorCode_Success) + { + return true; + } + else if (error == OrthancPluginErrorCode_UnknownResource || + error == OrthancPluginErrorCode_InexistentItem) + { + return false; + } + else + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); + } + } + + + void LogError(const std::string& message) + { + if (HasGlobalContext()) + { + OrthancPluginLogError(GetGlobalContext(), message.c_str()); + } + } + + + void LogWarning(const std::string& message) + { + if (HasGlobalContext()) + { + OrthancPluginLogWarning(GetGlobalContext(), message.c_str()); + } + } + + + void LogInfo(const std::string& message) + { + if (HasGlobalContext()) + { + OrthancPluginLogInfo(GetGlobalContext(), message.c_str()); + } + } + + + void OrthancConfiguration::LoadConfiguration() + { + OrthancString str; + str.Assign(OrthancPluginGetConfiguration(GetGlobalContext())); + + if (str.GetContent() == NULL) + { + LogError("Cannot access the Orthanc configuration"); + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + str.ToJson(configuration_); + + if (configuration_.type() != Json::objectValue) + { + LogError("Unable to read the Orthanc configuration"); + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + } + + + OrthancConfiguration::OrthancConfiguration() + { + LoadConfiguration(); + } + + + OrthancConfiguration::OrthancConfiguration(bool loadConfiguration) + { + if (loadConfiguration) + { + LoadConfiguration(); + } + else + { + configuration_ = Json::objectValue; + } + } + + + std::string OrthancConfiguration::GetPath(const std::string& key) const + { + if (path_.empty()) + { + return key; + } + else + { + return path_ + "." + key; + } + } + + + bool OrthancConfiguration::IsSection(const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + return (configuration_.isMember(key) && + configuration_[key].type() == Json::objectValue); + } + + + void OrthancConfiguration::GetSection(OrthancConfiguration& target, + const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + target.path_ = GetPath(key); + + if (!configuration_.isMember(key)) + { + target.configuration_ = Json::objectValue; + } + else + { + if (configuration_[key].type() != Json::objectValue) + { + LogError("The configuration section \"" + target.path_ + + "\" is not an associative array as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + + target.configuration_ = configuration_[key]; + } + } + + + bool OrthancConfiguration::LookupStringValue(std::string& target, + const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + if (!configuration_.isMember(key)) + { + return false; + } + + if (configuration_[key].type() != Json::stringValue) + { + LogError("The configuration option \"" + GetPath(key) + + "\" is not a string as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + + target = configuration_[key].asString(); + return true; + } + + + bool OrthancConfiguration::LookupIntegerValue(int& target, + const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + if (!configuration_.isMember(key)) + { + return false; + } + + switch (configuration_[key].type()) + { + case Json::intValue: + target = configuration_[key].asInt(); + return true; + + case Json::uintValue: + target = configuration_[key].asUInt(); + return true; + + default: + LogError("The configuration option \"" + GetPath(key) + + "\" is not an integer as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + } + + + bool OrthancConfiguration::LookupUnsignedIntegerValue(unsigned int& target, + const std::string& key) const + { + int tmp; + if (!LookupIntegerValue(tmp, key)) + { + return false; + } + + if (tmp < 0) + { + LogError("The configuration option \"" + GetPath(key) + + "\" is not a positive integer as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + else + { + target = static_cast(tmp); + return true; + } + } + + + bool OrthancConfiguration::LookupBooleanValue(bool& target, + const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + if (!configuration_.isMember(key)) + { + return false; + } + + if (configuration_[key].type() != Json::booleanValue) + { + LogError("The configuration option \"" + GetPath(key) + + "\" is not a Boolean as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + + target = configuration_[key].asBool(); + return true; + } + + + bool OrthancConfiguration::LookupFloatValue(float& target, + const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + if (!configuration_.isMember(key)) + { + return false; + } + + switch (configuration_[key].type()) + { + case Json::realValue: + target = configuration_[key].asFloat(); + return true; + + case Json::intValue: + target = static_cast(configuration_[key].asInt()); + return true; + + case Json::uintValue: + target = static_cast(configuration_[key].asUInt()); + return true; + + default: + LogError("The configuration option \"" + GetPath(key) + + "\" is not an integer as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + } + + + bool OrthancConfiguration::LookupListOfStrings(std::list& target, + const std::string& key, + bool allowSingleString) const + { + assert(configuration_.type() == Json::objectValue); + + target.clear(); + + if (!configuration_.isMember(key)) + { + return false; + } + + switch (configuration_[key].type()) + { + case Json::arrayValue: + { + bool ok = true; + + for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++) + { + if (configuration_[key][i].type() == Json::stringValue) + { + target.push_back(configuration_[key][i].asString()); + } + else + { + ok = false; + } + } + + if (ok) + { + return true; + } + + break; + } + + case Json::stringValue: + if (allowSingleString) + { + target.push_back(configuration_[key].asString()); + return true; + } + + break; + + default: + break; + } + + LogError("The configuration option \"" + GetPath(key) + + "\" is not a list of strings as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + + + bool OrthancConfiguration::LookupSetOfStrings(std::set& target, + const std::string& key, + bool allowSingleString) const + { + std::list lst; + + if (LookupListOfStrings(lst, key, allowSingleString)) + { + target.clear(); + + for (std::list::const_iterator + it = lst.begin(); it != lst.end(); ++it) + { + target.insert(*it); + } + + return true; + } + else + { + return false; + } + } + + + std::string OrthancConfiguration::GetStringValue(const std::string& key, + const std::string& defaultValue) const + { + std::string tmp; + if (LookupStringValue(tmp, key)) + { + return tmp; + } + else + { + return defaultValue; + } + } + + + int OrthancConfiguration::GetIntegerValue(const std::string& key, + int defaultValue) const + { + int tmp; + if (LookupIntegerValue(tmp, key)) + { + return tmp; + } + else + { + return defaultValue; + } + } + + + unsigned int OrthancConfiguration::GetUnsignedIntegerValue(const std::string& key, + unsigned int defaultValue) const + { + unsigned int tmp; + if (LookupUnsignedIntegerValue(tmp, key)) + { + return tmp; + } + else + { + return defaultValue; + } + } + + + bool OrthancConfiguration::GetBooleanValue(const std::string& key, + bool defaultValue) const + { + bool tmp; + if (LookupBooleanValue(tmp, key)) + { + return tmp; + } + else + { + return defaultValue; + } + } + + + float OrthancConfiguration::GetFloatValue(const std::string& key, + float defaultValue) const + { + float tmp; + if (LookupFloatValue(tmp, key)) + { + return tmp; + } + else + { + return defaultValue; + } + } + + + void OrthancConfiguration::GetDictionary(std::map& target, + const std::string& key) const + { + assert(configuration_.type() == Json::objectValue); + + target.clear(); + + if (!configuration_.isMember(key)) + { + return; + } + + if (configuration_[key].type() != Json::objectValue) + { + LogError("The configuration option \"" + GetPath(key) + + "\" is not a string as expected"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + + Json::Value::Members members = configuration_[key].getMemberNames(); + + for (size_t i = 0; i < members.size(); i++) + { + const Json::Value& value = configuration_[key][members[i]]; + + if (value.type() == Json::stringValue) + { + target[members[i]] = value.asString(); + } + else + { + LogError("The configuration option \"" + GetPath(key) + + "\" is not a dictionary mapping strings to strings"); + + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + } + } + + + void OrthancImage::Clear() + { + if (image_ != NULL) + { + OrthancPluginFreeImage(GetGlobalContext(), image_); + image_ = NULL; + } + } + + + void OrthancImage::CheckImageAvailable() const + { + if (image_ == NULL) + { + LogError("Trying to access a NULL image"); + ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); + } + } + + + OrthancImage::OrthancImage() : + image_(NULL) + { + } + + + OrthancImage::OrthancImage(OrthancPluginImage* image) : + image_(image) + { + } + + + OrthancImage::OrthancImage(OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height) + { + image_ = OrthancPluginCreateImage(GetGlobalContext(), format, width, height); + + if (image_ == NULL) + { + LogError("Cannot create an image"); + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + } + + + OrthancImage::OrthancImage(OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + void* buffer) + { + image_ = OrthancPluginCreateImageAccessor + (GetGlobalContext(), format, width, height, pitch, buffer); + + if (image_ == NULL) + { + LogError("Cannot create an image accessor"); + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + } + + void OrthancImage::UncompressPngImage(const void* data, + size_t size) + { + Clear(); + + image_ = OrthancPluginUncompressImage(GetGlobalContext(), data, size, OrthancPluginImageFormat_Png); + + if (image_ == NULL) + { + LogError("Cannot uncompress a PNG image"); + ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); + } + } + + + void OrthancImage::UncompressJpegImage(const void* data, + size_t size) + { + Clear(); + image_ = OrthancPluginUncompressImage(GetGlobalContext(), data, size, OrthancPluginImageFormat_Jpeg); + if (image_ == NULL) + { + LogError("Cannot uncompress a JPEG image"); + ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); + } + } + + + void OrthancImage::DecodeDicomImage(const void* data, + size_t size, + unsigned int frame) + { + Clear(); + image_ = OrthancPluginDecodeDicomImage(GetGlobalContext(), data, size, frame); + if (image_ == NULL) + { + LogError("Cannot uncompress a DICOM image"); + ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); + } + } + + + OrthancPluginPixelFormat OrthancImage::GetPixelFormat() const + { + CheckImageAvailable(); + return OrthancPluginGetImagePixelFormat(GetGlobalContext(), image_); + } + + + unsigned int OrthancImage::GetWidth() const + { + CheckImageAvailable(); + return OrthancPluginGetImageWidth(GetGlobalContext(), image_); + } + + + unsigned int OrthancImage::GetHeight() const + { + CheckImageAvailable(); + return OrthancPluginGetImageHeight(GetGlobalContext(), image_); + } + + + unsigned int OrthancImage::GetPitch() const + { + CheckImageAvailable(); + return OrthancPluginGetImagePitch(GetGlobalContext(), image_); + } + + + void* OrthancImage::GetBuffer() const + { + CheckImageAvailable(); + return OrthancPluginGetImageBuffer(GetGlobalContext(), image_); + } + + + void OrthancImage::CompressPngImage(MemoryBuffer& target) const + { + CheckImageAvailable(); + + OrthancPlugins::MemoryBuffer answer; + OrthancPluginCompressPngImage(GetGlobalContext(), *answer, GetPixelFormat(), + GetWidth(), GetHeight(), GetPitch(), GetBuffer()); + + target.Swap(answer); + } + + + void OrthancImage::CompressJpegImage(MemoryBuffer& target, + uint8_t quality) const + { + CheckImageAvailable(); + + OrthancPlugins::MemoryBuffer answer; + OrthancPluginCompressJpegImage(GetGlobalContext(), *answer, GetPixelFormat(), + GetWidth(), GetHeight(), GetPitch(), GetBuffer(), quality); + + target.Swap(answer); + } + + + void OrthancImage::AnswerPngImage(OrthancPluginRestOutput* output) const + { + CheckImageAvailable(); + OrthancPluginCompressAndAnswerPngImage(GetGlobalContext(), output, GetPixelFormat(), + GetWidth(), GetHeight(), GetPitch(), GetBuffer()); + } + + + void OrthancImage::AnswerJpegImage(OrthancPluginRestOutput* output, + uint8_t quality) const + { + CheckImageAvailable(); + OrthancPluginCompressAndAnswerJpegImage(GetGlobalContext(), output, GetPixelFormat(), + GetWidth(), GetHeight(), GetPitch(), GetBuffer(), quality); + } + + + OrthancPluginImage* OrthancImage::Release() + { + CheckImageAvailable(); + OrthancPluginImage* tmp = image_; + image_ = NULL; + return tmp; + } + + +#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 + FindMatcher::FindMatcher(const OrthancPluginWorklistQuery* worklist) : + matcher_(NULL), + worklist_(worklist) + { + if (worklist_ == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); + } + } + + + void FindMatcher::SetupDicom(const void* query, + uint32_t size) + { + worklist_ = NULL; + + matcher_ = OrthancPluginCreateFindMatcher(GetGlobalContext(), query, size); + if (matcher_ == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + } + + + FindMatcher::~FindMatcher() + { + // The "worklist_" field + + if (matcher_ != NULL) + { + OrthancPluginFreeFindMatcher(GetGlobalContext(), matcher_); + } + } + + + + bool FindMatcher::IsMatch(const void* dicom, + uint32_t size) const + { + int32_t result; + + if (matcher_ != NULL) + { + result = OrthancPluginFindMatcherIsMatch(GetGlobalContext(), matcher_, dicom, size); + } + else if (worklist_ != NULL) + { + result = OrthancPluginWorklistIsMatch(GetGlobalContext(), worklist_, dicom, size); + } + else + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + if (result == 0) + { + return false; + } + else if (result == 1) + { + return true; + } + else + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + } + +#endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */ + + void AnswerJson(const Json::Value& value, + OrthancPluginRestOutput* output + ) + { + Json::StyledWriter writer; + std::string bodyString = writer.write(value); + + OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json"); + } + + void AnswerString(const std::string& answer, + const char* mimeType, + OrthancPluginRestOutput* output + ) + { + OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType); + } + + void AnswerHttpError(uint16_t httpError, OrthancPluginRestOutput *output) + { + OrthancPluginSendHttpStatusCode(GetGlobalContext(), output, httpError); + } + + void AnswerMethodNotAllowed(OrthancPluginRestOutput *output, const char* allowedMethods) + { + OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowedMethods); + } + + bool RestApiGetString(std::string& result, + const std::string& uri, + bool applyPlugins) + { + MemoryBuffer answer; + if (!answer.RestApiGet(uri, applyPlugins)) + { + return false; + } + else + { + answer.ToString(result); + return true; + } + } + + bool RestApiGetString(std::string& result, + const std::string& uri, + const std::map& httpHeaders, + bool applyPlugins) + { + MemoryBuffer answer; + if (!answer.RestApiGet(uri, httpHeaders, applyPlugins)) + { + return false; + } + else + { + answer.ToString(result); + return true; + } + } + + + + bool RestApiGet(Json::Value& result, + const std::string& uri, + bool applyPlugins) + { + MemoryBuffer answer; + + if (!answer.RestApiGet(uri, applyPlugins)) + { + return false; + } + else + { + if (!answer.IsEmpty()) + { + answer.ToJson(result); + } + return true; + } + } + + + bool RestApiPost(std::string& result, + const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins) + { + MemoryBuffer answer; + + if (!answer.RestApiPost(uri, body, bodySize, applyPlugins)) + { + return false; + } + else + { + if (!answer.IsEmpty()) + { + result.assign(answer.GetData(), answer.GetSize()); + } + return true; + } + } + + + bool RestApiPost(Json::Value& result, + const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins) + { + MemoryBuffer answer; + + if (!answer.RestApiPost(uri, body, bodySize, applyPlugins)) + { + return false; + } + else + { + if (!answer.IsEmpty()) + { + answer.ToJson(result); + } + return true; + } + } + + + bool RestApiPost(Json::Value& result, + const std::string& uri, + const Json::Value& body, + bool applyPlugins) + { + Json::FastWriter writer; + return RestApiPost(result, uri, writer.write(body), applyPlugins); + } + + + bool RestApiPut(Json::Value& result, + const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins) + { + MemoryBuffer answer; + + if (!answer.RestApiPut(uri, body, bodySize, applyPlugins)) + { + return false; + } + else + { + if (!answer.IsEmpty()) // i.e, on a PUT to metadata/..., orthanc returns an empty response + { + answer.ToJson(result); + } + return true; + } + } + + + bool RestApiPut(Json::Value& result, + const std::string& uri, + const Json::Value& body, + bool applyPlugins) + { + Json::FastWriter writer; + return RestApiPut(result, uri, writer.write(body), applyPlugins); + } + + + bool RestApiDelete(const std::string& uri, + bool applyPlugins) + { + OrthancPluginErrorCode error; + + if (applyPlugins) + { + error = OrthancPluginRestApiDeleteAfterPlugins(GetGlobalContext(), uri.c_str()); + } + else + { + error = OrthancPluginRestApiDelete(GetGlobalContext(), uri.c_str()); + } + + if (error == OrthancPluginErrorCode_Success) + { + return true; + } + else if (error == OrthancPluginErrorCode_UnknownResource || + error == OrthancPluginErrorCode_InexistentItem) + { + return false; + } + else + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); + } + } + + + void ReportMinimalOrthancVersion(unsigned int major, + unsigned int minor, + unsigned int revision) + { + LogError("Your version of the Orthanc core (" + + std::string(GetGlobalContext()->orthancVersion) + + ") is too old to run this plugin (version " + + boost::lexical_cast(major) + "." + + boost::lexical_cast(minor) + "." + + boost::lexical_cast(revision) + + " is required)"); + } + + + bool CheckMinimalOrthancVersion(unsigned int major, + unsigned int minor, + unsigned int revision) + { + if (!HasGlobalContext()) + { + LogError("Bad Orthanc context in the plugin"); + return false; + } + + if (!strcmp(GetGlobalContext()->orthancVersion, "mainline")) + { + // Assume compatibility with the mainline + return true; + } + + // Parse the version of the Orthanc core + int aa, bb, cc; + if ( +#ifdef _MSC_VER + sscanf_s +#else + sscanf +#endif + (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 || + aa < 0 || + bb < 0 || + cc < 0) + { + return false; + } + + unsigned int a = static_cast(aa); + unsigned int b = static_cast(bb); + unsigned int c = static_cast(cc); + + // Check the major version number + + if (a > major) + { + return true; + } + + if (a < major) + { + return false; + } + + + // Check the minor version number + assert(a == major); + + if (b > minor) + { + return true; + } + + if (b < minor) + { + return false; + } + + // Check the patch level version number + assert(a == major && b == minor); + + if (c >= revision) + { + return true; + } + else + { + return false; + } + } + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) + const char* AutodetectMimeType(const std::string& path) + { + const char* mime = OrthancPluginAutodetectMimeType(GetGlobalContext(), path.c_str()); + + if (mime == NULL) + { + // Should never happen, just for safety + return "application/octet-stream"; + } + else + { + return mime; + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_PEERS == 1 + size_t OrthancPeers::GetPeerIndex(const std::string& name) const + { + size_t index; + if (LookupName(index, name)) + { + return index; + } + else + { + LogError("Inexistent peer: " + name); + ORTHANC_PLUGINS_THROW_EXCEPTION(UnknownResource); + } + } + + + OrthancPeers::OrthancPeers() : + peers_(NULL), + timeout_(0) + { + peers_ = OrthancPluginGetPeers(GetGlobalContext()); + + if (peers_ == NULL) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); + } + + uint32_t count = OrthancPluginGetPeersCount(GetGlobalContext(), peers_); + + for (uint32_t i = 0; i < count; i++) + { + const char* name = OrthancPluginGetPeerName(GetGlobalContext(), peers_, i); + if (name == NULL) + { + OrthancPluginFreePeers(GetGlobalContext(), peers_); + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); + } + + index_[name] = i; + } + } + + + OrthancPeers::~OrthancPeers() + { + if (peers_ != NULL) + { + OrthancPluginFreePeers(GetGlobalContext(), peers_); + } + } + + + bool OrthancPeers::LookupName(size_t& target, + const std::string& name) const + { + Index::const_iterator found = index_.find(name); + + if (found == index_.end()) + { + return false; + } + else + { + target = found->second; + return true; + } + } + + + std::string OrthancPeers::GetPeerName(size_t index) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + else + { + const char* s = OrthancPluginGetPeerName(GetGlobalContext(), peers_, static_cast(index)); + if (s == NULL) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); + } + else + { + return s; + } + } + } + + + std::string OrthancPeers::GetPeerUrl(size_t index) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + else + { + const char* s = OrthancPluginGetPeerUrl(GetGlobalContext(), peers_, static_cast(index)); + if (s == NULL) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); + } + else + { + return s; + } + } + } + + + std::string OrthancPeers::GetPeerUrl(const std::string& name) const + { + return GetPeerUrl(GetPeerIndex(name)); + } + + + bool OrthancPeers::LookupUserProperty(std::string& value, + size_t index, + const std::string& key) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + else + { + const char* s = OrthancPluginGetPeerUserProperty(GetGlobalContext(), peers_, static_cast(index), key.c_str()); + if (s == NULL) + { + return false; + } + else + { + value.assign(s); + return true; + } + } + } + + + bool OrthancPeers::LookupUserProperty(std::string& value, + const std::string& peer, + const std::string& key) const + { + return LookupUserProperty(value, GetPeerIndex(peer), key); + } + + + bool OrthancPeers::DoGet(MemoryBuffer& target, + size_t index, + const std::string& uri) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + + OrthancPlugins::MemoryBuffer answer; + uint16_t status; + OrthancPluginErrorCode code = OrthancPluginCallPeerApi + (GetGlobalContext(), *answer, NULL, &status, peers_, + static_cast(index), OrthancPluginHttpMethod_Get, uri.c_str(), + 0, NULL, NULL, NULL, 0, timeout_); + + if (code == OrthancPluginErrorCode_Success) + { + target.Swap(answer); + return (status == 200); + } + else + { + return false; + } + } + + + bool OrthancPeers::DoGet(MemoryBuffer& target, + const std::string& name, + const std::string& uri) const + { + size_t index; + return (LookupName(index, name) && + DoGet(target, index, uri)); + } + + + bool OrthancPeers::DoGet(Json::Value& target, + size_t index, + const std::string& uri) const + { + MemoryBuffer buffer; + + if (DoGet(buffer, index, uri)) + { + buffer.ToJson(target); + return true; + } + else + { + return false; + } + } + + + bool OrthancPeers::DoGet(Json::Value& target, + const std::string& name, + const std::string& uri) const + { + MemoryBuffer buffer; + + if (DoGet(buffer, name, uri)) + { + buffer.ToJson(target); + return true; + } + else + { + return false; + } + } + + + bool OrthancPeers::DoPost(MemoryBuffer& target, + const std::string& name, + const std::string& uri, + const std::string& body) const + { + size_t index; + return (LookupName(index, name) && + DoPost(target, index, uri, body)); + } + + + bool OrthancPeers::DoPost(Json::Value& target, + size_t index, + const std::string& uri, + const std::string& body) const + { + MemoryBuffer buffer; + + if (DoPost(buffer, index, uri, body)) + { + buffer.ToJson(target); + return true; + } + else + { + return false; + } + } + + + bool OrthancPeers::DoPost(Json::Value& target, + const std::string& name, + const std::string& uri, + const std::string& body) const + { + MemoryBuffer buffer; + + if (DoPost(buffer, name, uri, body)) + { + buffer.ToJson(target); + return true; + } + else + { + return false; + } + } + + + bool OrthancPeers::DoPost(MemoryBuffer& target, + size_t index, + const std::string& uri, + const std::string& body) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + + OrthancPlugins::MemoryBuffer answer; + uint16_t status; + OrthancPluginErrorCode code = OrthancPluginCallPeerApi + (GetGlobalContext(), *answer, NULL, &status, peers_, + static_cast(index), OrthancPluginHttpMethod_Post, uri.c_str(), + 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); + + if (code == OrthancPluginErrorCode_Success) + { + target.Swap(answer); + return (status == 200); + } + else + { + return false; + } + } + + + bool OrthancPeers::DoPut(size_t index, + const std::string& uri, + const std::string& body) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + + OrthancPlugins::MemoryBuffer answer; + uint16_t status; + OrthancPluginErrorCode code = OrthancPluginCallPeerApi + (GetGlobalContext(), *answer, NULL, &status, peers_, + static_cast(index), OrthancPluginHttpMethod_Put, uri.c_str(), + 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); + + if (code == OrthancPluginErrorCode_Success) + { + return (status == 200); + } + else + { + return false; + } + } + + + bool OrthancPeers::DoPut(const std::string& name, + const std::string& uri, + const std::string& body) const + { + size_t index; + return (LookupName(index, name) && + DoPut(index, uri, body)); + } + + + bool OrthancPeers::DoDelete(size_t index, + const std::string& uri) const + { + if (index >= index_.size()) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + + OrthancPlugins::MemoryBuffer answer; + uint16_t status; + OrthancPluginErrorCode code = OrthancPluginCallPeerApi + (GetGlobalContext(), *answer, NULL, &status, peers_, + static_cast(index), OrthancPluginHttpMethod_Delete, uri.c_str(), + 0, NULL, NULL, NULL, 0, timeout_); + + if (code == OrthancPluginErrorCode_Success) + { + return (status == 200); + } + else + { + return false; + } + } + + + bool OrthancPeers::DoDelete(const std::string& name, + const std::string& uri) const + { + size_t index; + return (LookupName(index, name) && + DoDelete(index, uri)); + } +#endif + + + + + + /****************************************************************** + ** JOBS + ******************************************************************/ + +#if HAS_ORTHANC_PLUGIN_JOB == 1 + void OrthancJob::CallbackFinalize(void* job) + { + if (job != NULL) + { + delete reinterpret_cast(job); + } + } + + + float OrthancJob::CallbackGetProgress(void* job) + { + assert(job != NULL); + + try + { + return reinterpret_cast(job)->progress_; + } + catch (...) + { + return 0; + } + } + + + const char* OrthancJob::CallbackGetContent(void* job) + { + assert(job != NULL); + + try + { + return reinterpret_cast(job)->content_.c_str(); + } + catch (...) + { + return 0; + } + } + + + const char* OrthancJob::CallbackGetSerialized(void* job) + { + assert(job != NULL); + + try + { + const OrthancJob& tmp = *reinterpret_cast(job); + + if (tmp.hasSerialized_) + { + return tmp.serialized_.c_str(); + } + else + { + return NULL; + } + } + catch (...) + { + return 0; + } + } + + + OrthancPluginJobStepStatus OrthancJob::CallbackStep(void* job) + { + assert(job != NULL); + + try + { + return reinterpret_cast(job)->Step(); + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS&) + { + return OrthancPluginJobStepStatus_Failure; + } + catch (...) + { + return OrthancPluginJobStepStatus_Failure; + } + } + + + OrthancPluginErrorCode OrthancJob::CallbackStop(void* job, + OrthancPluginJobStopReason reason) + { + assert(job != NULL); + + try + { + reinterpret_cast(job)->Stop(reason); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } + + + OrthancPluginErrorCode OrthancJob::CallbackReset(void* job) + { + assert(job != NULL); + + try + { + reinterpret_cast(job)->Reset(); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } + + + void OrthancJob::ClearContent() + { + Json::Value empty = Json::objectValue; + UpdateContent(empty); + } + + + void OrthancJob::UpdateContent(const Json::Value& content) + { + if (content.type() != Json::objectValue) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat); + } + else + { + Json::FastWriter writer; + content_ = writer.write(content); + } + } + + + void OrthancJob::ClearSerialized() + { + hasSerialized_ = false; + serialized_.clear(); + } + + + void OrthancJob::UpdateSerialized(const Json::Value& serialized) + { + if (serialized.type() != Json::objectValue) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_BadFileFormat); + } + else + { + Json::FastWriter writer; + serialized_ = writer.write(serialized); + hasSerialized_ = true; + } + } + + + void OrthancJob::UpdateProgress(float progress) + { + if (progress < 0 || + progress > 1) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); + } + + progress_ = progress; + } + + + OrthancJob::OrthancJob(const std::string& jobType) : + jobType_(jobType), + progress_(0) + { + ClearContent(); + ClearSerialized(); + } + + + OrthancPluginJob* OrthancJob::Create(OrthancJob* job) + { + if (job == NULL) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); + } + + OrthancPluginJob* orthanc = OrthancPluginCreateJob( + GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(), + CallbackGetProgress, CallbackGetContent, CallbackGetSerialized, + CallbackStep, CallbackStop, CallbackReset); + + if (orthanc == NULL) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); + } + else + { + return orthanc; + } + } + + + std::string OrthancJob::Submit(OrthancJob* job, + int priority) + { + if (job == NULL) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); + } + + OrthancPluginJob* orthanc = Create(job); + + char* id = OrthancPluginSubmitJob(GetGlobalContext(), orthanc, priority); + + if (id == NULL) + { + LogError("Plugin cannot submit job"); + OrthancPluginFreeJob(GetGlobalContext(), orthanc); + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); + } + else + { + std::string tmp(id); + tmp.assign(id); + OrthancPluginFreeString(GetGlobalContext(), id); + + return tmp; + } + } + + + void OrthancJob::SubmitAndWait(Json::Value& result, + OrthancJob* job /* takes ownership */, + int priority) + { + std::string id = Submit(job, priority); + + for (;;) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + + Json::Value status; + if (!RestApiGet(status, "/jobs/" + id, false) || + !status.isMember("State") || + status["State"].type() != Json::stringValue) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InexistentItem); + } + + const std::string state = status["State"].asString(); + if (state == "Success") + { + if (status.isMember("Content")) + { + result = status["Content"]; + } + else + { + result = Json::objectValue; + } + + return; + } + else if (state == "Running") + { + continue; + } + else if (!status.isMember("ErrorCode") || + status["ErrorCode"].type() != Json::intValue) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_InternalError); + } + else + { + if (!status.isMember("ErrorDescription") || + status["ErrorDescription"].type() != Json::stringValue) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(status["ErrorCode"].asInt()); + } + else + { +#if HAS_ORTHANC_EXCEPTION == 1 + throw Orthanc::OrthancException(static_cast(status["ErrorCode"].asInt()), + status["ErrorDescription"].asString()); +#else + LogError("Exception while executing the job: " + status["ErrorDescription"].asString()); + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(status["ErrorCode"].asInt()); +#endif + } + } + } + } + + + void OrthancJob::SubmitFromRestApiPost(OrthancPluginRestOutput* output, + const Json::Value& body, + OrthancJob* job) + { + static const char* KEY_SYNCHRONOUS = "Synchronous"; + static const char* KEY_ASYNCHRONOUS = "Asynchronous"; + static const char* KEY_PRIORITY = "Priority"; + + boost::movelib::unique_ptr protection(job); + + if (body.type() != Json::objectValue) + { +#if HAS_ORTHANC_EXCEPTION == 1 + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Expected a JSON object in the body"); +#else + LogError("Expected a JSON object in the body"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); +#endif + } + + bool synchronous = true; + + if (body.isMember(KEY_SYNCHRONOUS)) + { + if (body[KEY_SYNCHRONOUS].type() != Json::booleanValue) + { +#if HAS_ORTHANC_EXCEPTION == 1 + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Option \"" + std::string(KEY_SYNCHRONOUS) + + "\" must be Boolean"); +#else + LogError("Option \"" + std::string(KEY_SYNCHRONOUS) + "\" must be Boolean"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); +#endif + } + else + { + synchronous = body[KEY_SYNCHRONOUS].asBool(); + } + } + + if (body.isMember(KEY_ASYNCHRONOUS)) + { + if (body[KEY_ASYNCHRONOUS].type() != Json::booleanValue) + { +#if HAS_ORTHANC_EXCEPTION == 1 + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Option \"" + std::string(KEY_ASYNCHRONOUS) + + "\" must be Boolean"); +#else + LogError("Option \"" + std::string(KEY_ASYNCHRONOUS) + "\" must be Boolean"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); +#endif + } + else + { + synchronous = !body[KEY_ASYNCHRONOUS].asBool(); + } + } + + int priority = 0; + + if (body.isMember(KEY_PRIORITY)) + { + if (body[KEY_PRIORITY].type() != Json::booleanValue) + { +#if HAS_ORTHANC_EXCEPTION == 1 + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, + "Option \"" + std::string(KEY_PRIORITY) + + "\" must be an integer"); +#else + LogError("Option \"" + std::string(KEY_PRIORITY) + "\" must be an integer"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); +#endif + } + else + { + priority = !body[KEY_PRIORITY].asInt(); + } + } + + Json::Value result; + + if (synchronous) + { + OrthancPlugins::OrthancJob::SubmitAndWait(result, protection.release(), priority); + } + else + { + std::string id = OrthancPlugins::OrthancJob::Submit(protection.release(), priority); + + result = Json::objectValue; + result["ID"] = id; + result["Path"] = "/jobs/" + id; + } + + std::string s = result.toStyledString(); + OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), + s.size(), "application/json"); + } + +#endif + + + + + /****************************************************************** + ** METRICS + ******************************************************************/ + +#if HAS_ORTHANC_PLUGIN_METRICS == 1 + MetricsTimer::MetricsTimer(const char* name) : + name_(name) + { + start_ = boost::posix_time::microsec_clock::universal_time(); + } + + MetricsTimer::~MetricsTimer() + { + const boost::posix_time::ptime stop = boost::posix_time::microsec_clock::universal_time(); + const boost::posix_time::time_duration diff = stop - start_; + OrthancPluginSetMetricsValue(GetGlobalContext(), name_.c_str(), static_cast(diff.total_milliseconds()), + OrthancPluginMetricsType_Timer); + } +#endif + + + + + /****************************************************************** + ** HTTP CLIENT + ******************************************************************/ + +#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 + class HttpClient::RequestBodyWrapper : public boost::noncopyable + { + private: + static RequestBodyWrapper& GetObject(void* body) + { + assert(body != NULL); + return *reinterpret_cast(body); + } + + IRequestBody& body_; + bool done_; + std::string chunk_; + + public: + RequestBodyWrapper(IRequestBody& body) : + body_(body), + done_(false) + { + } + + static uint8_t IsDone(void* body) + { + return GetObject(body).done_; + } + + static const void* GetChunkData(void* body) + { + return GetObject(body).chunk_.c_str(); + } + + static uint32_t GetChunkSize(void* body) + { + return static_cast(GetObject(body).chunk_.size()); + } + + static OrthancPluginErrorCode Next(void* body) + { + RequestBodyWrapper& that = GetObject(body); + + if (that.done_) + { + return OrthancPluginErrorCode_BadSequenceOfCalls; + } + else + { + try + { + that.done_ = !that.body_.ReadNextChunk(that.chunk_); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_InternalError; + } + } + } + }; + + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + static OrthancPluginErrorCode AnswerAddHeaderCallback(void* answer, + const char* key, + const char* value) + { + assert(answer != NULL && key != NULL && value != NULL); + + try + { + reinterpret_cast(answer)->AddHeader(key, value); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + static OrthancPluginErrorCode AnswerAddChunkCallback(void* answer, + const void* data, + uint32_t size) + { + assert(answer != NULL); + + try + { + reinterpret_cast(answer)->AddChunk(data, size); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } +#endif + + + HttpClient::HttpClient() : + httpStatus_(0), + method_(OrthancPluginHttpMethod_Get), + timeout_(0), + pkcs11_(false), + chunkedBody_(NULL), + allowChunkedTransfers_(true) + { + } + + + void HttpClient::AddHeaders(const HttpHeaders& headers) + { + for (HttpHeaders::const_iterator it = headers.begin(); + it != headers.end(); ++it) + { + headers_[it->first] = it->second; + } + } + + + void HttpClient::SetCredentials(const std::string& username, + const std::string& password) + { + username_ = username; + password_ = password; + } + + + void HttpClient::ClearCredentials() + { + username_.empty(); + password_.empty(); + } + + + void HttpClient::SetCertificate(const std::string& certificateFile, + const std::string& keyFile, + const std::string& keyPassword) + { + certificateFile_ = certificateFile; + certificateKeyFile_ = keyFile; + certificateKeyPassword_ = keyPassword; + } + + + void HttpClient::ClearCertificate() + { + certificateFile_.clear(); + certificateKeyFile_.clear(); + certificateKeyPassword_.clear(); + } + + + void HttpClient::ClearBody() + { + fullBody_.clear(); + chunkedBody_ = NULL; + } + + + void HttpClient::SwapBody(std::string& body) + { + fullBody_.swap(body); + chunkedBody_ = NULL; + } + + + void HttpClient::SetBody(const std::string& body) + { + fullBody_ = body; + chunkedBody_ = NULL; + } + + + void HttpClient::SetBody(IRequestBody& body) + { + fullBody_.clear(); + chunkedBody_ = &body; + } + + + namespace + { + class HeadersWrapper : public boost::noncopyable + { + private: + std::vector headersKeys_; + std::vector headersValues_; + + public: + HeadersWrapper(const HttpClient::HttpHeaders& headers) + { + headersKeys_.reserve(headers.size()); + headersValues_.reserve(headers.size()); + + for (HttpClient::HttpHeaders::const_iterator it = headers.begin(); it != headers.end(); ++it) + { + headersKeys_.push_back(it->first.c_str()); + headersValues_.push_back(it->second.c_str()); + } + } + + void AddStaticString(const char* key, + const char* value) + { + headersKeys_.push_back(key); + headersValues_.push_back(value); + } + + uint32_t GetCount() const + { + return headersKeys_.size(); + } + + const char* const* GetKeys() const + { + return headersKeys_.empty() ? NULL : &headersKeys_[0]; + } + + const char* const* GetValues() const + { + return headersValues_.empty() ? NULL : &headersValues_[0]; + } + }; + + + class MemoryRequestBody : public HttpClient::IRequestBody + { + private: + std::string body_; + bool done_; + + public: + MemoryRequestBody(const std::string& body) : + body_(body), + done_(false) + { + if (body_.empty()) + { + done_ = true; + } + } + + virtual bool ReadNextChunk(std::string& chunk) + { + if (done_) + { + return false; + } + else + { + chunk.swap(body_); + done_ = true; + return true; + } + } + }; + + + // This class mimics Orthanc::ChunkedBuffer + class ChunkedBuffer : public boost::noncopyable + { + private: + typedef std::list Content; + + Content content_; + size_t size_; + + public: + ChunkedBuffer() : + size_(0) + { + } + + ~ChunkedBuffer() + { + Clear(); + } + + void Clear() + { + for (Content::iterator it = content_.begin(); it != content_.end(); ++it) + { + assert(*it != NULL); + delete *it; + } + + content_.clear(); + } + + void Flatten(std::string& target) const + { + target.resize(size_); + + size_t pos = 0; + + for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) + { + assert(*it != NULL); + size_t s = (*it)->size(); + + if (s != 0) + { + memcpy(&target[pos], (*it)->c_str(), s); + pos += s; + } + } + + assert(size_ == 0 || + pos == target.size()); + } + + void AddChunk(const void* data, + size_t size) + { + content_.push_back(new std::string(reinterpret_cast(data), size)); + size_ += size; + } + + void AddChunk(const std::string& chunk) + { + content_.push_back(new std::string(chunk)); + size_ += chunk.size(); + } + }; + + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + class MemoryAnswer : public HttpClient::IAnswer + { + private: + HttpClient::HttpHeaders headers_; + ChunkedBuffer body_; + + public: + const HttpClient::HttpHeaders& GetHeaders() const + { + return headers_; + } + + const ChunkedBuffer& GetBody() const + { + return body_; + } + + virtual void AddHeader(const std::string& key, + const std::string& value) + { + headers_[key] = value; + } + + virtual void AddChunk(const void* data, + size_t size) + { + body_.AddChunk(data, size); + } + }; +#endif + } + + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + void HttpClient::ExecuteWithStream(uint16_t& httpStatus, + IAnswer& answer, + IRequestBody& body) const + { + HeadersWrapper h(headers_); + + if (method_ == OrthancPluginHttpMethod_Post || + method_ == OrthancPluginHttpMethod_Put) + { + // Automatically set the "Transfer-Encoding" header if absent + bool found = false; + + for (HttpHeaders::const_iterator it = headers_.begin(); it != headers_.end(); ++it) + { + if (boost::iequals(it->first, "Transfer-Encoding")) + { + found = true; + break; + } + } + + if (!found) + { + h.AddStaticString("Transfer-Encoding", "chunked"); + } + } + + RequestBodyWrapper request(body); + + OrthancPluginErrorCode error = OrthancPluginChunkedHttpClient( + GetGlobalContext(), + &answer, + AnswerAddChunkCallback, + AnswerAddHeaderCallback, + &httpStatus, + method_, + url_.c_str(), + h.GetCount(), + h.GetKeys(), + h.GetValues(), + &request, + RequestBodyWrapper::IsDone, + RequestBodyWrapper::GetChunkData, + RequestBodyWrapper::GetChunkSize, + RequestBodyWrapper::Next, + username_.empty() ? NULL : username_.c_str(), + password_.empty() ? NULL : password_.c_str(), + timeout_, + certificateFile_.empty() ? NULL : certificateFile_.c_str(), + certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(), + certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(), + pkcs11_ ? 1 : 0); + + if (error != OrthancPluginErrorCode_Success) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); + } + } +#endif + + + void HttpClient::ExecuteWithoutStream(uint16_t& httpStatus, + HttpHeaders& answerHeaders, + std::string& answerBody, + const std::string& body) const + { + HeadersWrapper headers(headers_); + + MemoryBuffer answerBodyBuffer, answerHeadersBuffer; + + OrthancPluginErrorCode error = OrthancPluginHttpClient( + GetGlobalContext(), + *answerBodyBuffer, + *answerHeadersBuffer, + &httpStatus, + method_, + url_.c_str(), + headers.GetCount(), + headers.GetKeys(), + headers.GetValues(), + body.empty() ? NULL : body.c_str(), + body.size(), + username_.empty() ? NULL : username_.c_str(), + password_.empty() ? NULL : password_.c_str(), + timeout_, + certificateFile_.empty() ? NULL : certificateFile_.c_str(), + certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(), + certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(), + pkcs11_ ? 1 : 0); + + if (error != OrthancPluginErrorCode_Success) + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error); + } + + Json::Value v; + answerHeadersBuffer.ToJson(v); + + if (v.type() != Json::objectValue) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + Json::Value::Members members = v.getMemberNames(); + answerHeaders.clear(); + + for (size_t i = 0; i < members.size(); i++) + { + const Json::Value& h = v[members[i]]; + if (h.type() != Json::stringValue) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + else + { + answerHeaders[members[i]] = h.asString(); + } + } + + answerBodyBuffer.ToString(answerBody); + } + + + void HttpClient::Execute(IAnswer& answer) + { +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + if (allowChunkedTransfers_) + { + if (chunkedBody_ != NULL) + { + ExecuteWithStream(httpStatus_, answer, *chunkedBody_); + } + else + { + MemoryRequestBody wrapper(fullBody_); + ExecuteWithStream(httpStatus_, answer, wrapper); + } + + return; + } +#endif + + // Compatibility mode for Orthanc SDK <= 1.5.6 or if chunked + // transfers are disabled. This results in higher memory usage + // (all chunks from the answer body are sent at once) + + HttpHeaders answerHeaders; + std::string answerBody; + Execute(answerHeaders, answerBody); + + for (HttpHeaders::const_iterator it = answerHeaders.begin(); + it != answerHeaders.end(); ++it) + { + answer.AddHeader(it->first, it->second); + } + + if (!answerBody.empty()) + { + answer.AddChunk(answerBody.c_str(), answerBody.size()); + } + } + + + void HttpClient::Execute(HttpHeaders& answerHeaders /* out */, + std::string& answerBody /* out */) + { +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + if (allowChunkedTransfers_) + { + MemoryAnswer answer; + Execute(answer); + answerHeaders = answer.GetHeaders(); + answer.GetBody().Flatten(answerBody); + return; + } +#endif + + // Compatibility mode for Orthanc SDK <= 1.5.6 or if chunked + // transfers are disabled. This results in higher memory usage + // (all chunks from the request body are sent at once) + + if (chunkedBody_ != NULL) + { + ChunkedBuffer buffer; + + std::string chunk; + while (chunkedBody_->ReadNextChunk(chunk)) + { + buffer.AddChunk(chunk); + } + + std::string body; + buffer.Flatten(body); + + ExecuteWithoutStream(httpStatus_, answerHeaders, answerBody, body); + } + else + { + ExecuteWithoutStream(httpStatus_, answerHeaders, answerBody, fullBody_); + } + } + + + void HttpClient::Execute(HttpHeaders& answerHeaders /* out */, + Json::Value& answerBody /* out */) + { + std::string body; + Execute(answerHeaders, body); + + Json::Reader reader; + if (!reader.parse(body, answerBody)) + { + LogError("Cannot convert HTTP answer body to JSON"); + ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); + } + } + + + void HttpClient::Execute() + { + HttpHeaders answerHeaders; + std::string body; + Execute(answerHeaders, body); + } + +#endif /* HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 */ + + + + + + /****************************************************************** + ** CHUNKED HTTP SERVER + ******************************************************************/ + + namespace Internals + { + void NullRestCallback(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) + { + } + + IChunkedRequestReader *NullChunkedRestCallback(const char* url, + const OrthancPluginHttpRequest* request) + { + return NULL; + } + + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 + + OrthancPluginErrorCode ChunkedRequestReaderAddChunk( + OrthancPluginServerChunkedRequestReader* reader, + const void* data, + uint32_t size) + { + try + { + if (reader == NULL) + { + return OrthancPluginErrorCode_InternalError; + } + + reinterpret_cast(reader)->AddChunk(data, size); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + return OrthancPluginErrorCode_BadFileFormat; + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } + + + OrthancPluginErrorCode ChunkedRequestReaderExecute( + OrthancPluginServerChunkedRequestReader* reader, + OrthancPluginRestOutput* output) + { + try + { + if (reader == NULL) + { + return OrthancPluginErrorCode_InternalError; + } + + reinterpret_cast(reader)->Execute(output); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + return OrthancPluginErrorCode_BadFileFormat; + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } + + + void ChunkedRequestReaderFinalize( + OrthancPluginServerChunkedRequestReader* reader) + { + if (reader != NULL) + { + delete reinterpret_cast(reader); + } + } + +#else + + OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request, + RestCallback GetHandler, + ChunkedRestCallback PostHandler, + RestCallback DeleteHandler, + ChunkedRestCallback PutHandler) + { + try + { + std::string allowed; + + if (GetHandler != Internals::NullRestCallback) + { + allowed += "GET"; + } + + if (PostHandler != Internals::NullChunkedRestCallback) + { + if (!allowed.empty()) + { + allowed += ","; + } + + allowed += "POST"; + } + + if (DeleteHandler != Internals::NullRestCallback) + { + if (!allowed.empty()) + { + allowed += ","; + } + + allowed += "DELETE"; + } + + if (PutHandler != Internals::NullChunkedRestCallback) + { + if (!allowed.empty()) + { + allowed += ","; + } + + allowed += "PUT"; + } + + switch (request->method) + { + case OrthancPluginHttpMethod_Get: + if (GetHandler == Internals::NullRestCallback) + { + OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); + } + else + { + GetHandler(output, url, request); + } + + break; + + case OrthancPluginHttpMethod_Post: + if (PostHandler == Internals::NullChunkedRestCallback) + { + OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); + } + else + { + boost::movelib::unique_ptr reader(PostHandler(url, request)); + if (reader.get() == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); + } + else + { + reader->AddChunk(request->body, request->bodySize); + reader->Execute(output); + } + } + + break; + + case OrthancPluginHttpMethod_Delete: + if (DeleteHandler == Internals::NullRestCallback) + { + OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); + } + else + { + DeleteHandler(output, url, request); + } + + break; + + case OrthancPluginHttpMethod_Put: + if (PutHandler == Internals::NullChunkedRestCallback) + { + OrthancPluginSendMethodNotAllowed(GetGlobalContext(), output, allowed.c_str()); + } + else + { + boost::movelib::unique_ptr reader(PutHandler(url, request)); + if (reader.get() == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); + } + else + { + reader->AddChunk(request->body, request->bodySize); + reader->Execute(output); + } + } + + break; + + default: + ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); + } + + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { +#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1 + if (HasGlobalContext() && + e.HasDetails()) + { + // The "false" instructs Orthanc not to log the detailed + // error message. This is to avoid duplicating the details, + // because "OrthancException" already does it on construction. + OrthancPluginSetHttpErrorDetails + (GetGlobalContext(), output, e.GetDetails(), false); + } +#endif + + return static_cast(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + return OrthancPluginErrorCode_BadFileFormat; + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } +#endif + } + + +#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1 + OrthancPluginErrorCode IStorageCommitmentScpHandler::Lookup( + OrthancPluginStorageCommitmentFailureReason* target, + void* rawHandler, + const char* sopClassUid, + const char* sopInstanceUid) + { + assert(target != NULL && + rawHandler != NULL); + + try + { + IStorageCommitmentScpHandler& handler = *reinterpret_cast(rawHandler); + *target = handler.Lookup(sopClassUid, sopInstanceUid); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } +#endif + + +#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1 + void IStorageCommitmentScpHandler::Destructor(void* rawHandler) + { + assert(rawHandler != NULL); + delete reinterpret_cast(rawHandler); + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + DicomInstance::DicomInstance(const OrthancPluginDicomInstance* instance) : + toFree_(false), + instance_(instance) + { + } +#else + DicomInstance::DicomInstance(OrthancPluginDicomInstance* instance) : + toFree_(false), + instance_(instance) + { + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + DicomInstance::DicomInstance(const void* buffer, + size_t size) : + toFree_(true), + instance_(OrthancPluginCreateDicomInstance(GetGlobalContext(), buffer, size)) + { + if (instance_ == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(NullPointer); + } + } +#endif + + + DicomInstance::~DicomInstance() + { +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + if (toFree_ && + instance_ != NULL) + { + OrthancPluginFreeDicomInstance( + GetGlobalContext(), const_cast(instance_)); + } +#endif + } + + + std::string DicomInstance::GetRemoteAet() const + { + const char* s = OrthancPluginGetInstanceRemoteAet(GetGlobalContext(), instance_); + if (s == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); + } + else + { + return std::string(s); + } + } + + + void DicomInstance::GetJson(Json::Value& target) const + { + OrthancString s; + s.Assign(OrthancPluginGetInstanceJson(GetGlobalContext(), instance_)); + s.ToJson(target); + } + + + void DicomInstance::GetSimplifiedJson(Json::Value& target) const + { + OrthancString s; + s.Assign(OrthancPluginGetInstanceSimplifiedJson(GetGlobalContext(), instance_)); + s.ToJson(target); + } + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + std::string DicomInstance::GetTransferSyntaxUid() const + { + OrthancString s; + s.Assign(OrthancPluginGetInstanceTransferSyntaxUid(GetGlobalContext(), instance_)); + + std::string result; + s.ToString(result); + return result; + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + bool DicomInstance::HasPixelData() const + { + int32_t result = OrthancPluginHasInstancePixelData(GetGlobalContext(), instance_); + if (result < 0) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); + } + else + { + return (result != 0); + } + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + void DicomInstance::GetRawFrame(std::string& target, + unsigned int frameIndex) const + { + MemoryBuffer buffer; + OrthancPluginErrorCode code = OrthancPluginGetInstanceRawFrame( + GetGlobalContext(), *buffer, instance_, frameIndex); + + if (code == OrthancPluginErrorCode_Success) + { + buffer.ToString(target); + } + else + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); + } + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + OrthancImage* DicomInstance::GetDecodedFrame(unsigned int frameIndex) const + { + OrthancPluginImage* image = OrthancPluginGetInstanceDecodedFrame( + GetGlobalContext(), instance_, frameIndex); + + if (image == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); + } + else + { + return new OrthancImage(image); + } + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + void DicomInstance::Serialize(std::string& target) const + { + MemoryBuffer buffer; + OrthancPluginErrorCode code = OrthancPluginSerializeDicomInstance( + GetGlobalContext(), *buffer, instance_); + + if (code == OrthancPluginErrorCode_Success) + { + buffer.ToString(target); + } + else + { + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code); + } + } +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + DicomInstance* DicomInstance::Transcode(const void* buffer, + size_t size, + const std::string& transferSyntax) + { + OrthancPluginDicomInstance* instance = OrthancPluginTranscodeDicomInstance( + GetGlobalContext(), buffer, size, transferSyntax.c_str()); + + if (instance == NULL) + { + ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin); + } + else + { + boost::movelib::unique_ptr result(new DicomInstance(instance)); + result->toFree_ = true; + return result.release(); + } + } +#endif +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h --- orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,1228 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "OrthancPluginException.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/** + * The definition of ORTHANC_PLUGINS_VERSION_IS_ABOVE below is for + * backward compatibility with Orthanc SDK <= 1.3.0. + * + * $ hg diff -r Orthanc-1.3.0:Orthanc-1.3.1 ../../../Plugins/Include/orthanc/OrthancCPlugin.h + * + **/ +#if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) +#define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \ + (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \ + (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \ + (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \ + (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \ + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision)))) +#endif + + +#if !defined(ORTHANC_FRAMEWORK_VERSION_IS_ABOVE) +#define ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(major, minor, revision) \ + (ORTHANC_VERSION_MAJOR > major || \ + (ORTHANC_VERSION_MAJOR == major && \ + (ORTHANC_VERSION_MINOR > minor || \ + (ORTHANC_VERSION_MINOR == minor && \ + ORTHANC_VERSION_REVISION >= revision)))) +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0) +// The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0 +# define HAS_ORTHANC_PLUGIN_FIND_MATCHER 1 +#else +# define HAS_ORTHANC_PLUGIN_FIND_MATCHER 0 +#endif + + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 4, 2) +# define HAS_ORTHANC_PLUGIN_PEERS 1 +# define HAS_ORTHANC_PLUGIN_JOB 1 +#else +# define HAS_ORTHANC_PLUGIN_PEERS 0 +# define HAS_ORTHANC_PLUGIN_JOB 0 +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) +# define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 1 +#else +# define HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS 0 +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4) +# define HAS_ORTHANC_PLUGIN_METRICS 1 +#else +# define HAS_ORTHANC_PLUGIN_METRICS 0 +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 1, 0) +# define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 1 +#else +# define HAS_ORTHANC_PLUGIN_HTTP_CLIENT 0 +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7) +# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 1 +#else +# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT 0 +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 7) +# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 1 +#else +# define HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER 0 +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 0) +# define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 1 +#else +# define HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP 0 +#endif + + + +namespace OrthancPlugins +{ + typedef void (*RestCallback) (OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request); + + void SetGlobalContext(OrthancPluginContext* context); + + bool HasGlobalContext(); + + OrthancPluginContext* GetGlobalContext(); + + + class OrthancImage; + + + class MemoryBuffer : public boost::noncopyable + { + private: + OrthancPluginMemoryBuffer buffer_; + + void Check(OrthancPluginErrorCode code); + + bool CheckHttp(OrthancPluginErrorCode code); + + public: + MemoryBuffer(); + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + // This constructor makes a copy of the given buffer in the memory + // handled by the Orthanc core + MemoryBuffer(const void* buffer, + size_t size); +#endif + + ~MemoryBuffer() + { + Clear(); + } + + OrthancPluginMemoryBuffer* operator*() + { + return &buffer_; + } + + // This transfers ownership from "other" to "this" + void Assign(OrthancPluginMemoryBuffer& other); + + void Swap(MemoryBuffer& other); + + OrthancPluginMemoryBuffer Release(); + + const char* GetData() const + { + if (buffer_.size > 0) + { + return reinterpret_cast(buffer_.data); + } + else + { + return NULL; + } + } + + size_t GetSize() const + { + return buffer_.size; + } + + bool IsEmpty() const + { + return GetSize() == 0 || GetData() == NULL; + } + + void Clear(); + + void ToString(std::string& target) const; + + void ToJson(Json::Value& target) const; + + bool RestApiGet(const std::string& uri, + bool applyPlugins); + + bool RestApiGet(const std::string& uri, + const std::map& httpHeaders, + bool applyPlugins); + + bool RestApiPost(const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins); + + bool RestApiPut(const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins); + + bool RestApiPost(const std::string& uri, + const Json::Value& body, + bool applyPlugins); + + bool RestApiPut(const std::string& uri, + const Json::Value& body, + bool applyPlugins); + + bool RestApiPost(const std::string& uri, + const std::string& body, + bool applyPlugins) + { + return RestApiPost(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins); + } + + bool RestApiPut(const std::string& uri, + const std::string& body, + bool applyPlugins) + { + return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins); + } + + void CreateDicom(const Json::Value& tags, + OrthancPluginCreateDicomFlags flags); + + void CreateDicom(const Json::Value& tags, + const OrthancImage& pixelData, + OrthancPluginCreateDicomFlags flags); + + void ReadFile(const std::string& path); + + void GetDicomQuery(const OrthancPluginWorklistQuery* query); + + void DicomToJson(Json::Value& target, + OrthancPluginDicomToJsonFormat format, + OrthancPluginDicomToJsonFlags flags, + uint32_t maxStringLength); + + bool HttpGet(const std::string& url, + const std::string& username, + const std::string& password); + + bool HttpPost(const std::string& url, + const std::string& body, + const std::string& username, + const std::string& password); + + bool HttpPut(const std::string& url, + const std::string& body, + const std::string& username, + const std::string& password); + + void GetDicomInstance(const std::string& instanceId); + }; + + + class OrthancString : public boost::noncopyable + { + private: + char* str_; + + void Clear(); + + public: + OrthancString() : + str_(NULL) + { + } + + ~OrthancString() + { + Clear(); + } + + // This transfers ownership, warning: The string must have been + // allocated by the Orthanc core + void Assign(char* str); + + const char* GetContent() const + { + return str_; + } + + void ToString(std::string& target) const; + + void ToJson(Json::Value& target) const; + }; + + + class OrthancConfiguration : public boost::noncopyable + { + private: + Json::Value configuration_; // Necessarily a Json::objectValue + std::string path_; + + std::string GetPath(const std::string& key) const; + + void LoadConfiguration(); + + public: + OrthancConfiguration(); + + explicit OrthancConfiguration(bool load); + + const Json::Value& GetJson() const + { + return configuration_; + } + + bool IsSection(const std::string& key) const; + + void GetSection(OrthancConfiguration& target, + const std::string& key) const; + + bool LookupStringValue(std::string& target, + const std::string& key) const; + + bool LookupIntegerValue(int& target, + const std::string& key) const; + + bool LookupUnsignedIntegerValue(unsigned int& target, + const std::string& key) const; + + bool LookupBooleanValue(bool& target, + const std::string& key) const; + + bool LookupFloatValue(float& target, + const std::string& key) const; + + bool LookupListOfStrings(std::list& target, + const std::string& key, + bool allowSingleString) const; + + bool LookupSetOfStrings(std::set& target, + const std::string& key, + bool allowSingleString) const; + + std::string GetStringValue(const std::string& key, + const std::string& defaultValue) const; + + int GetIntegerValue(const std::string& key, + int defaultValue) const; + + unsigned int GetUnsignedIntegerValue(const std::string& key, + unsigned int defaultValue) const; + + bool GetBooleanValue(const std::string& key, + bool defaultValue) const; + + float GetFloatValue(const std::string& key, + float defaultValue) const; + + void GetDictionary(std::map& target, + const std::string& key) const; + }; + + class OrthancImage : public boost::noncopyable + { + private: + OrthancPluginImage* image_; + + void Clear(); + + void CheckImageAvailable() const; + + public: + OrthancImage(); + + explicit OrthancImage(OrthancPluginImage* image); + + OrthancImage(OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height); + + OrthancImage(OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + void* buffer); + + ~OrthancImage() + { + Clear(); + } + + void UncompressPngImage(const void* data, + size_t size); + + void UncompressJpegImage(const void* data, + size_t size); + + void DecodeDicomImage(const void* data, + size_t size, + unsigned int frame); + + OrthancPluginPixelFormat GetPixelFormat() const; + + unsigned int GetWidth() const; + + unsigned int GetHeight() const; + + unsigned int GetPitch() const; + + void* GetBuffer() const; + + const OrthancPluginImage* GetObject() const + { + return image_; + } + + void CompressPngImage(MemoryBuffer& target) const; + + void CompressJpegImage(MemoryBuffer& target, + uint8_t quality) const; + + void AnswerPngImage(OrthancPluginRestOutput* output) const; + + void AnswerJpegImage(OrthancPluginRestOutput* output, + uint8_t quality) const; + + void* GetWriteableBuffer(); + + OrthancPluginImage* Release(); + }; + + +#if HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 + class FindMatcher : public boost::noncopyable + { + private: + OrthancPluginFindMatcher* matcher_; + const OrthancPluginWorklistQuery* worklist_; + + void SetupDicom(const void* query, + uint32_t size); + + public: + explicit FindMatcher(const OrthancPluginWorklistQuery* worklist); + + FindMatcher(const void* query, + uint32_t size) + { + SetupDicom(query, size); + } + + explicit FindMatcher(const MemoryBuffer& dicom) + { + SetupDicom(dicom.GetData(), dicom.GetSize()); + } + + ~FindMatcher(); + + bool IsMatch(const void* dicom, + uint32_t size) const; + + bool IsMatch(const MemoryBuffer& dicom) const + { + return IsMatch(dicom.GetData(), dicom.GetSize()); + } + }; +#endif + + + bool RestApiGet(Json::Value& result, + const std::string& uri, + bool applyPlugins); + + bool RestApiGetString(std::string& result, + const std::string& uri, + bool applyPlugins); + + bool RestApiGetString(std::string& result, + const std::string& uri, + const std::map& httpHeaders, + bool applyPlugins); + + bool RestApiPost(std::string& result, + const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins); + + bool RestApiPost(Json::Value& result, + const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins); + + bool RestApiPost(Json::Value& result, + const std::string& uri, + const Json::Value& body, + bool applyPlugins); + + inline bool RestApiPost(Json::Value& result, + const std::string& uri, + const std::string& body, + bool applyPlugins) + { + return RestApiPost(result, uri, body.empty() ? NULL : body.c_str(), + body.size(), applyPlugins); + } + + inline bool RestApiPost(Json::Value& result, + const std::string& uri, + const MemoryBuffer& body, + bool applyPlugins) + { + return RestApiPost(result, uri, body.GetData(), + body.GetSize(), applyPlugins); + } + + bool RestApiPut(Json::Value& result, + const std::string& uri, + const void* body, + size_t bodySize, + bool applyPlugins); + + bool RestApiPut(Json::Value& result, + const std::string& uri, + const Json::Value& body, + bool applyPlugins); + + inline bool RestApiPut(Json::Value& result, + const std::string& uri, + const std::string& body, + bool applyPlugins) + { + return RestApiPut(result, uri, body.empty() ? NULL : body.c_str(), + body.size(), applyPlugins); + } + + bool RestApiDelete(const std::string& uri, + bool applyPlugins); + + bool HttpDelete(const std::string& url, + const std::string& username, + const std::string& password); + + void AnswerJson(const Json::Value& value, + OrthancPluginRestOutput* output); + + void AnswerString(const std::string& answer, + const char* mimeType, + OrthancPluginRestOutput* output); + + void AnswerHttpError(uint16_t httpError, + OrthancPluginRestOutput* output); + + void AnswerMethodNotAllowed(OrthancPluginRestOutput* output, const char* allowedMethods); + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) + const char* AutodetectMimeType(const std::string& path); +#endif + + void LogError(const std::string& message); + + void LogWarning(const std::string& message); + + void LogInfo(const std::string& message); + + void ReportMinimalOrthancVersion(unsigned int major, + unsigned int minor, + unsigned int revision); + + bool CheckMinimalOrthancVersion(unsigned int major, + unsigned int minor, + unsigned int revision); + + + namespace Internals + { + template + static OrthancPluginErrorCode Protect(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) + { + try + { + Callback(output, url, request); + return OrthancPluginErrorCode_Success; + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { +#if HAS_ORTHANC_EXCEPTION == 1 && HAS_ORTHANC_PLUGIN_EXCEPTION_DETAILS == 1 + if (HasGlobalContext() && + e.HasDetails()) + { + // The "false" instructs Orthanc not to log the detailed + // error message. This is to avoid duplicating the details, + // because "OrthancException" already does it on construction. + OrthancPluginSetHttpErrorDetails + (GetGlobalContext(), output, e.GetDetails(), false); + } +#endif + + return static_cast(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + return OrthancPluginErrorCode_BadFileFormat; + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } + } + + + template + void RegisterRestCallback(const std::string& uri, + bool isThreadSafe) + { + if (isThreadSafe) + { + OrthancPluginRegisterRestCallbackNoLock + (GetGlobalContext(), uri.c_str(), Internals::Protect); + } + else + { + OrthancPluginRegisterRestCallback + (GetGlobalContext(), uri.c_str(), Internals::Protect); + } + } + + +#if HAS_ORTHANC_PLUGIN_PEERS == 1 + class OrthancPeers : public boost::noncopyable + { + private: + typedef std::map Index; + + OrthancPluginPeers *peers_; + Index index_; + uint32_t timeout_; + + size_t GetPeerIndex(const std::string& name) const; + + public: + OrthancPeers(); + + ~OrthancPeers(); + + uint32_t GetTimeout() const + { + return timeout_; + } + + void SetTimeout(uint32_t timeout) + { + timeout_ = timeout; + } + + bool LookupName(size_t& target, + const std::string& name) const; + + std::string GetPeerName(size_t index) const; + + std::string GetPeerUrl(size_t index) const; + + std::string GetPeerUrl(const std::string& name) const; + + size_t GetPeersCount() const + { + return index_.size(); + } + + bool LookupUserProperty(std::string& value, + size_t index, + const std::string& key) const; + + bool LookupUserProperty(std::string& value, + const std::string& peer, + const std::string& key) const; + + bool DoGet(MemoryBuffer& target, + size_t index, + const std::string& uri) const; + + bool DoGet(MemoryBuffer& target, + const std::string& name, + const std::string& uri) const; + + bool DoGet(Json::Value& target, + size_t index, + const std::string& uri) const; + + bool DoGet(Json::Value& target, + const std::string& name, + const std::string& uri) const; + + bool DoPost(MemoryBuffer& target, + size_t index, + const std::string& uri, + const std::string& body) const; + + bool DoPost(MemoryBuffer& target, + const std::string& name, + const std::string& uri, + const std::string& body) const; + + bool DoPost(Json::Value& target, + size_t index, + const std::string& uri, + const std::string& body) const; + + bool DoPost(Json::Value& target, + const std::string& name, + const std::string& uri, + const std::string& body) const; + + bool DoPut(size_t index, + const std::string& uri, + const std::string& body) const; + + bool DoPut(const std::string& name, + const std::string& uri, + const std::string& body) const; + + bool DoDelete(size_t index, + const std::string& uri) const; + + bool DoDelete(const std::string& name, + const std::string& uri) const; + }; +#endif + + + +#if HAS_ORTHANC_PLUGIN_JOB == 1 + class OrthancJob : public boost::noncopyable + { + private: + std::string jobType_; + std::string content_; + bool hasSerialized_; + std::string serialized_; + float progress_; + + static void CallbackFinalize(void* job); + + static float CallbackGetProgress(void* job); + + static const char* CallbackGetContent(void* job); + + static const char* CallbackGetSerialized(void* job); + + static OrthancPluginJobStepStatus CallbackStep(void* job); + + static OrthancPluginErrorCode CallbackStop(void* job, + OrthancPluginJobStopReason reason); + + static OrthancPluginErrorCode CallbackReset(void* job); + + protected: + void ClearContent(); + + void UpdateContent(const Json::Value& content); + + void ClearSerialized(); + + void UpdateSerialized(const Json::Value& serialized); + + void UpdateProgress(float progress); + + public: + explicit OrthancJob(const std::string& jobType); + + virtual ~OrthancJob() + { + } + + virtual OrthancPluginJobStepStatus Step() = 0; + + virtual void Stop(OrthancPluginJobStopReason reason) = 0; + + virtual void Reset() = 0; + + static OrthancPluginJob* Create(OrthancJob* job /* takes ownership */); + + static std::string Submit(OrthancJob* job /* takes ownership */, + int priority); + + static void SubmitAndWait(Json::Value& result, + OrthancJob* job /* takes ownership */, + int priority); + + // Submit a job from a POST on the REST API with the same + // conventions as in the Orthanc core (according to the + // "Synchronous" and "Priority" options) + static void SubmitFromRestApiPost(OrthancPluginRestOutput* output, + const Json::Value& body, + OrthancJob* job); + }; +#endif + + +#if HAS_ORTHANC_PLUGIN_METRICS == 1 + inline void SetMetricsValue(char* name, + float value) + { + OrthancPluginSetMetricsValue(GetGlobalContext(), name, + value, OrthancPluginMetricsType_Default); + } + + class MetricsTimer : public boost::noncopyable + { + private: + std::string name_; + boost::posix_time::ptime start_; + + public: + explicit MetricsTimer(const char* name); + + ~MetricsTimer(); + }; +#endif + + +#if HAS_ORTHANC_PLUGIN_HTTP_CLIENT == 1 + class HttpClient : public boost::noncopyable + { + public: + typedef std::map HttpHeaders; + + class IRequestBody : public boost::noncopyable + { + public: + virtual ~IRequestBody() + { + } + + virtual bool ReadNextChunk(std::string& chunk) = 0; + }; + + + class IAnswer : public boost::noncopyable + { + public: + virtual ~IAnswer() + { + } + + virtual void AddHeader(const std::string& key, + const std::string& value) = 0; + + virtual void AddChunk(const void* data, + size_t size) = 0; + }; + + + private: + class RequestBodyWrapper; + + uint16_t httpStatus_; + OrthancPluginHttpMethod method_; + std::string url_; + HttpHeaders headers_; + std::string username_; + std::string password_; + uint32_t timeout_; + std::string certificateFile_; + std::string certificateKeyFile_; + std::string certificateKeyPassword_; + bool pkcs11_; + std::string fullBody_; + IRequestBody* chunkedBody_; + bool allowChunkedTransfers_; + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_CLIENT == 1 + void ExecuteWithStream(uint16_t& httpStatus, // out + IAnswer& answer, // out + IRequestBody& body) const; +#endif + + void ExecuteWithoutStream(uint16_t& httpStatus, // out + HttpHeaders& answerHeaders, // out + std::string& answerBody, // out + const std::string& body) const; + + public: + HttpClient(); + + uint16_t GetHttpStatus() const + { + return httpStatus_; + } + + void SetMethod(OrthancPluginHttpMethod method) + { + method_ = method; + } + + const std::string& GetUrl() const + { + return url_; + } + + void SetUrl(const std::string& url) + { + url_ = url; + } + + void SetHeaders(const HttpHeaders& headers) + { + headers_ = headers; + } + + void AddHeader(const std::string& key, + const std::string& value) + { + headers_[key] = value; + } + + void AddHeaders(const HttpHeaders& headers); + + void SetCredentials(const std::string& username, + const std::string& password); + + void ClearCredentials(); + + void SetTimeout(unsigned int timeout) // 0 for default timeout + { + timeout_ = timeout; + } + + void SetCertificate(const std::string& certificateFile, + const std::string& keyFile, + const std::string& keyPassword); + + void ClearCertificate(); + + void SetPkcs11(bool pkcs11) + { + pkcs11_ = pkcs11; + } + + void ClearBody(); + + void SwapBody(std::string& body); + + void SetBody(const std::string& body); + + void SetBody(IRequestBody& body); + + // This function can be used to disable chunked transfers if the + // remote server is Orthanc with a version <= 1.5.6. + void SetChunkedTransfersAllowed(bool allow) + { + allowChunkedTransfers_ = allow; + } + + bool IsChunkedTransfersAllowed() const + { + return allowChunkedTransfers_; + } + + void Execute(IAnswer& answer); + + void Execute(HttpHeaders& answerHeaders /* out */, + std::string& answerBody /* out */); + + void Execute(HttpHeaders& answerHeaders /* out */, + Json::Value& answerBody /* out */); + + void Execute(); + }; +#endif + + + + class IChunkedRequestReader : public boost::noncopyable + { + public: + virtual ~IChunkedRequestReader() + { + } + + virtual void AddChunk(const void* data, + size_t size) = 0; + + virtual void Execute(OrthancPluginRestOutput* output) = 0; + }; + + + typedef IChunkedRequestReader* (*ChunkedRestCallback) (const char* url, + const OrthancPluginHttpRequest* request); + + + namespace Internals + { + void NullRestCallback(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request); + + IChunkedRequestReader *NullChunkedRestCallback(const char* url, + const OrthancPluginHttpRequest* request); + + +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 + template + static OrthancPluginErrorCode ChunkedProtect(OrthancPluginServerChunkedRequestReader** reader, + const char* url, + const OrthancPluginHttpRequest* request) + { + try + { + if (reader == NULL) + { + return OrthancPluginErrorCode_InternalError; + } + else + { + *reader = reinterpret_cast(Callback(url, request)); + if (*reader == NULL) + { + return OrthancPluginErrorCode_Plugin; + } + else + { + return OrthancPluginErrorCode_Success; + } + } + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + return static_cast(e.GetErrorCode()); + } + catch (boost::bad_lexical_cast&) + { + return OrthancPluginErrorCode_BadFileFormat; + } + catch (...) + { + return OrthancPluginErrorCode_Plugin; + } + } + + OrthancPluginErrorCode ChunkedRequestReaderAddChunk( + OrthancPluginServerChunkedRequestReader* reader, + const void* data, + uint32_t size); + + OrthancPluginErrorCode ChunkedRequestReaderExecute( + OrthancPluginServerChunkedRequestReader* reader, + OrthancPluginRestOutput* output); + + void ChunkedRequestReaderFinalize( + OrthancPluginServerChunkedRequestReader* reader); + +#else + + OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request, + RestCallback GetHandler, + ChunkedRestCallback PostHandler, + RestCallback DeleteHandler, + ChunkedRestCallback PutHandler); + + template< + RestCallback GetHandler, + ChunkedRestCallback PostHandler, + RestCallback DeleteHandler, + ChunkedRestCallback PutHandler + > + inline OrthancPluginErrorCode ChunkedRestCompatibility(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) + { + return ChunkedRestCompatibility(output, url, request, GetHandler, + PostHandler, DeleteHandler, PutHandler); + } +#endif + } + + + + // NB: We use a templated class instead of a templated function, because + // default values are only available in functions since C++11 + template< + RestCallback GetHandler = Internals::NullRestCallback, + ChunkedRestCallback PostHandler = Internals::NullChunkedRestCallback, + RestCallback DeleteHandler = Internals::NullRestCallback, + ChunkedRestCallback PutHandler = Internals::NullChunkedRestCallback + > + class ChunkedRestRegistration : public boost::noncopyable + { + public: + static void Apply(const std::string& uri) + { +#if HAS_ORTHANC_PLUGIN_CHUNKED_HTTP_SERVER == 1 + OrthancPluginRegisterChunkedRestCallback( + GetGlobalContext(), uri.c_str(), + GetHandler == Internals::NullRestCallback ? NULL : Internals::Protect, + PostHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect, + DeleteHandler == Internals::NullRestCallback ? NULL : Internals::Protect, + PutHandler == Internals::NullChunkedRestCallback ? NULL : Internals::ChunkedProtect, + Internals::ChunkedRequestReaderAddChunk, + Internals::ChunkedRequestReaderExecute, + Internals::ChunkedRequestReaderFinalize); +#else + OrthancPluginRegisterRestCallbackNoLock( + GetGlobalContext(), uri.c_str(), + Internals::ChunkedRestCompatibility); +#endif + } + }; + + + +#if HAS_ORTHANC_PLUGIN_STORAGE_COMMITMENT_SCP == 1 + class IStorageCommitmentScpHandler : public boost::noncopyable + { + public: + virtual ~IStorageCommitmentScpHandler() + { + } + + virtual OrthancPluginStorageCommitmentFailureReason Lookup(const std::string& sopClassUid, + const std::string& sopInstanceUid) = 0; + + static OrthancPluginErrorCode Lookup(OrthancPluginStorageCommitmentFailureReason* target, + void* rawHandler, + const char* sopClassUid, + const char* sopInstanceUid); + + static void Destructor(void* rawHandler); + }; +#endif + + + class DicomInstance : public boost::noncopyable + { + private: + bool toFree_; + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + const OrthancPluginDicomInstance* instance_; +#else + OrthancPluginDicomInstance* instance_; +#endif + + public: +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + explicit DicomInstance(const OrthancPluginDicomInstance* instance); +#else + explicit DicomInstance(OrthancPluginDicomInstance* instance); +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + DicomInstance(const void* buffer, + size_t size); +#endif + + ~DicomInstance(); + + std::string GetRemoteAet() const; + + const void* GetBuffer() const + { + return OrthancPluginGetInstanceData(GetGlobalContext(), instance_); + } + + size_t GetSize() const + { + return static_cast(OrthancPluginGetInstanceSize(GetGlobalContext(), instance_)); + } + + void GetJson(Json::Value& target) const; + + void GetSimplifiedJson(Json::Value& target) const; + + OrthancPluginInstanceOrigin GetOrigin() const + { + return OrthancPluginGetInstanceOrigin(GetGlobalContext(), instance_); + } + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + std::string GetTransferSyntaxUid() const; +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 6, 1) + bool HasPixelData() const; +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + unsigned int GetFramesCount() const + { + return OrthancPluginGetInstanceFramesCount(GetGlobalContext(), instance_); + } +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + void GetRawFrame(std::string& target, + unsigned int frameIndex) const; +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + OrthancImage* GetDecodedFrame(unsigned int frameIndex) const; +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + void Serialize(std::string& target) const; +#endif + +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0) + static DicomInstance* Transcode(const void* buffer, + size_t size, + const std::string& transferSyntax); +#endif + }; +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginException.h orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginException.h --- orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginException.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginException.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,89 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#if !defined(HAS_ORTHANC_EXCEPTION) +# error The macro HAS_ORTHANC_EXCEPTION must be defined +#endif + + +#if HAS_ORTHANC_EXCEPTION == 1 +# include +# define ORTHANC_PLUGINS_ERROR_ENUMERATION ::Orthanc::ErrorCode +# define ORTHANC_PLUGINS_EXCEPTION_CLASS ::Orthanc::OrthancException +# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::Orthanc::ErrorCode_ ## code +#else +# include +# define ORTHANC_PLUGINS_ERROR_ENUMERATION ::OrthancPluginErrorCode +# define ORTHANC_PLUGINS_EXCEPTION_CLASS ::OrthancPlugins::PluginException +# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::OrthancPluginErrorCode_ ## code +#endif + + +#define ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code) \ + throw ORTHANC_PLUGINS_EXCEPTION_CLASS(static_cast(code)); + + +#define ORTHANC_PLUGINS_THROW_EXCEPTION(code) \ + throw ORTHANC_PLUGINS_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code)); + + +#define ORTHANC_PLUGINS_CHECK_ERROR(code) \ + if (code != ORTHANC_PLUGINS_GET_ERROR_CODE(Success)) \ + { \ + ORTHANC_PLUGINS_THROW_EXCEPTION(code); \ + } + + +namespace OrthancPlugins +{ +#if HAS_ORTHANC_EXCEPTION == 0 + class PluginException + { + private: + OrthancPluginErrorCode code_; + + public: + explicit PluginException(OrthancPluginErrorCode code) : code_(code) + { + } + + OrthancPluginErrorCode GetErrorCode() const + { + return code_; + } + + const char* What(OrthancPluginContext* context) const + { + const char* description = OrthancPluginGetErrorDescription(context, code_); + if (description) + { + return description; + } + else + { + return "No description available"; + } + } + }; +#endif +} diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake --- orthanc-mysql-2.0/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Plugins/OrthancPluginsExports.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,31 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2020 Osimis S.A., Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +# In Orthanc <= 1.7.1, the instructions below were part of +# "Compiler.cmake", and were protected by the (now unused) option +# "ENABLE_PLUGINS_VERSION_SCRIPT" in CMake + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script=${CMAKE_CURRENT_LIST_DIR}/VersionScriptPlugins.map") +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${CMAKE_CURRENT_LIST_DIR}/ExportedSymbolsPlugins.list") +endif() diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Plugins/VersionScriptPlugins.map orthanc-mysql-3.0/Resources/Orthanc/Plugins/VersionScriptPlugins.map --- orthanc-mysql-2.0/Resources/Orthanc/Plugins/VersionScriptPlugins.map 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Plugins/VersionScriptPlugins.map 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,12 @@ +# This is a version-script for Orthanc plugins + +{ +global: + OrthancPluginInitialize; + OrthancPluginFinalize; + OrthancPluginGetName; + OrthancPluginGetVersion; + +local: + *; +}; diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCDatabasePlugin.h orthanc-mysql-3.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCDatabasePlugin.h --- orthanc-mysql-2.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCDatabasePlugin.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCDatabasePlugin.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,987 @@ +/** + * @ingroup CInterface + **/ + +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + + +#pragma once + +#include "OrthancCPlugin.h" + + +/** @{ */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + + /** + * Opaque structure that represents the context of a custom database engine. + * @ingroup Callbacks + **/ + typedef struct _OrthancPluginDatabaseContext_t OrthancPluginDatabaseContext; + + +/*InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerChange( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const OrthancPluginChange* change) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Change; + params.valueUint32 = 0; + params.valueGeneric = change; + + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerChangesDone( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Change; + params.valueUint32 = 1; + params.valueGeneric = NULL; + + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerInt32( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + int32_t value) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Int32; + params.valueInt32 = value; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerInt64( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + int64_t value) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Int64; + params.valueInt64 = value; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerExportedResource( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const OrthancPluginExportedResource* exported) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_ExportedResource; + params.valueUint32 = 0; + params.valueGeneric = exported; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerExportedResourcesDone( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_ExportedResource; + params.valueUint32 = 1; + params.valueGeneric = NULL; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerDicomTag( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const OrthancPluginDicomTag* tag) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_DicomTag; + params.valueGeneric = tag; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerAttachment( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const OrthancPluginAttachment* attachment) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Attachment; + params.valueGeneric = attachment; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerResource( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + int64_t id, + OrthancPluginResourceType resourceType) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Resource; + params.valueInt64 = id; + params.valueInt32 = (int32_t) resourceType; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerMatchingResource( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const OrthancPluginMatchingResource* match) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_MatchingResource; + params.valueGeneric = match; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerMetadata( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + int64_t resourceId, + int32_t type, + const char* value) + { + OrthancPluginResourcesContentMetadata metadata; + _OrthancPluginDatabaseAnswer params; + metadata.resource = resourceId; + metadata.metadata = type; + metadata.value = value; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_Metadata; + params.valueGeneric = &metadata; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseSignalDeletedAttachment( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const OrthancPluginAttachment* attachment) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_DeletedAttachment; + params.valueGeneric = attachment; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseSignalDeletedResource( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const char* publicId, + OrthancPluginResourceType resourceType) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_DeletedResource; + params.valueString = publicId; + params.valueInt32 = (int32_t) resourceType; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseSignalRemainingAncestor( + OrthancPluginContext* context, + OrthancPluginDatabaseContext* database, + const char* ancestorId, + OrthancPluginResourceType ancestorType) + { + _OrthancPluginDatabaseAnswer params; + memset(¶ms, 0, sizeof(params)); + params.database = database; + params.type = _OrthancPluginDatabaseAnswerType_RemainingAncestor; + params.valueString = ancestorId; + params.valueInt32 = (int32_t) ancestorType; + context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, ¶ms); + } + + + + + + typedef struct + { + OrthancPluginErrorCode (*addAttachment) ( + /* inputs */ + void* payload, + int64_t id, + const OrthancPluginAttachment* attachment); + + OrthancPluginErrorCode (*attachChild) ( + /* inputs */ + void* payload, + int64_t parent, + int64_t child); + + OrthancPluginErrorCode (*clearChanges) ( + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*clearExportedResources) ( + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*createResource) ( + /* outputs */ + int64_t* id, + /* inputs */ + void* payload, + const char* publicId, + OrthancPluginResourceType resourceType); + + OrthancPluginErrorCode (*deleteAttachment) ( + /* inputs */ + void* payload, + int64_t id, + int32_t contentType); + + OrthancPluginErrorCode (*deleteMetadata) ( + /* inputs */ + void* payload, + int64_t id, + int32_t metadataType); + + OrthancPluginErrorCode (*deleteResource) ( + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerString() */ + OrthancPluginErrorCode (*getAllPublicIds) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + OrthancPluginResourceType resourceType); + + /* Output: Use OrthancPluginDatabaseAnswerChange() and + * OrthancPluginDatabaseAnswerChangesDone() */ + OrthancPluginErrorCode (*getChanges) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t since, + uint32_t maxResult); + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*getChildrenInternalId) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerString() */ + OrthancPluginErrorCode (*getChildrenPublicId) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerExportedResource() and + * OrthancPluginDatabaseAnswerExportedResourcesDone() */ + OrthancPluginErrorCode (*getExportedResources) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t since, + uint32_t maxResult); + + /* Output: Use OrthancPluginDatabaseAnswerChange() */ + OrthancPluginErrorCode (*getLastChange) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload); + + /* Output: Use OrthancPluginDatabaseAnswerExportedResource() */ + OrthancPluginErrorCode (*getLastExportedResource) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload); + + /* Output: Use OrthancPluginDatabaseAnswerDicomTag() */ + OrthancPluginErrorCode (*getMainDicomTags) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerString() */ + OrthancPluginErrorCode (*getPublicId) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + OrthancPluginErrorCode (*getResourceCount) ( + /* outputs */ + uint64_t* target, + /* inputs */ + void* payload, + OrthancPluginResourceType resourceType); + + OrthancPluginErrorCode (*getResourceType) ( + /* outputs */ + OrthancPluginResourceType* resourceType, + /* inputs */ + void* payload, + int64_t id); + + OrthancPluginErrorCode (*getTotalCompressedSize) ( + /* outputs */ + uint64_t* target, + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*getTotalUncompressedSize) ( + /* outputs */ + uint64_t* target, + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*isExistingResource) ( + /* outputs */ + int32_t* existing, + /* inputs */ + void* payload, + int64_t id); + + OrthancPluginErrorCode (*isProtectedPatient) ( + /* outputs */ + int32_t* isProtected, + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerInt32() */ + OrthancPluginErrorCode (*listAvailableMetadata) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerInt32() */ + OrthancPluginErrorCode (*listAvailableAttachments) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + OrthancPluginErrorCode (*logChange) ( + /* inputs */ + void* payload, + const OrthancPluginChange* change); + + OrthancPluginErrorCode (*logExportedResource) ( + /* inputs */ + void* payload, + const OrthancPluginExportedResource* exported); + + /* Output: Use OrthancPluginDatabaseAnswerAttachment() */ + OrthancPluginErrorCode (*lookupAttachment) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id, + int32_t contentType); + + /* Output: Use OrthancPluginDatabaseAnswerString() */ + OrthancPluginErrorCode (*lookupGlobalProperty) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int32_t property); + + /* Use "OrthancPluginDatabaseExtensions::lookupIdentifier3" + instead of this function as of Orthanc 0.9.5 (db v6), can be set to NULL. + Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*lookupIdentifier) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + const OrthancPluginDicomTag* tag); + + /* Unused starting with Orthanc 0.9.5 (db v6), can be set to NULL. + Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*lookupIdentifier2) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + const char* value); + + /* Output: Use OrthancPluginDatabaseAnswerString() */ + OrthancPluginErrorCode (*lookupMetadata) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id, + int32_t metadata); + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*lookupParent) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerResource() */ + OrthancPluginErrorCode (*lookupResource) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + const char* publicId); + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*selectPatientToRecycle) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload); + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*selectPatientToRecycle2) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t patientIdToAvoid); + + OrthancPluginErrorCode (*setGlobalProperty) ( + /* inputs */ + void* payload, + int32_t property, + const char* value); + + OrthancPluginErrorCode (*setMainDicomTag) ( + /* inputs */ + void* payload, + int64_t id, + const OrthancPluginDicomTag* tag); + + OrthancPluginErrorCode (*setIdentifierTag) ( + /* inputs */ + void* payload, + int64_t id, + const OrthancPluginDicomTag* tag); + + OrthancPluginErrorCode (*setMetadata) ( + /* inputs */ + void* payload, + int64_t id, + int32_t metadata, + const char* value); + + OrthancPluginErrorCode (*setProtectedPatient) ( + /* inputs */ + void* payload, + int64_t id, + int32_t isProtected); + + OrthancPluginErrorCode (*startTransaction) ( + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*rollbackTransaction) ( + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*commitTransaction) ( + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*open) ( + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*close) ( + /* inputs */ + void* payload); + + } OrthancPluginDatabaseBackend; + + + typedef struct + { + /** + * Base extensions since Orthanc 1.0.0 + **/ + + /* Output: Use OrthancPluginDatabaseAnswerString() */ + OrthancPluginErrorCode (*getAllPublicIdsWithLimit) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + OrthancPluginResourceType resourceType, + uint64_t since, + uint64_t limit); + + OrthancPluginErrorCode (*getDatabaseVersion) ( + /* outputs */ + uint32_t* version, + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*upgradeDatabase) ( + /* inputs */ + void* payload, + uint32_t targetVersion, + OrthancPluginStorageArea* storageArea); + + OrthancPluginErrorCode (*clearMainDicomTags) ( + /* inputs */ + void* payload, + int64_t id); + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*getAllInternalIds) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + OrthancPluginResourceType resourceType); + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*lookupIdentifier3) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + OrthancPluginResourceType resourceType, + const OrthancPluginDicomTag* tag, + OrthancPluginIdentifierConstraint constraint); + + + /** + * Extensions since Orthanc 1.4.0 + **/ + + /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + OrthancPluginErrorCode (*lookupIdentifierRange) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + OrthancPluginResourceType resourceType, + uint16_t group, + uint16_t element, + const char* start, + const char* end); + + + /** + * Extensions since Orthanc 1.5.2 + **/ + + /* Ouput: Use OrthancPluginDatabaseAnswerMatchingResource */ + OrthancPluginErrorCode (*lookupResources) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + uint32_t constraintsCount, + const OrthancPluginDatabaseConstraint* constraints, + OrthancPluginResourceType queryLevel, + uint32_t limit, + uint8_t requestSomeInstance); + + OrthancPluginErrorCode (*createInstance) ( + /* output */ + OrthancPluginCreateInstanceResult* output, + /* inputs */ + void* payload, + const char* hashPatient, + const char* hashStudy, + const char* hashSeries, + const char* hashInstance); + + OrthancPluginErrorCode (*setResourcesContent) ( + /* inputs */ + void* payload, + uint32_t countIdentifierTags, + const OrthancPluginResourcesContentTags* identifierTags, + uint32_t countMainDicomTags, + const OrthancPluginResourcesContentTags* mainDicomTags, + uint32_t countMetadata, + const OrthancPluginResourcesContentMetadata* metadata); + + /* Ouput: Use OrthancPluginDatabaseAnswerString */ + OrthancPluginErrorCode (*getChildrenMetadata) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t resourceId, + int32_t metadata); + + OrthancPluginErrorCode (*getLastChangeIndex) ( + /* outputs */ + int64_t* target, + /* inputs */ + void* payload); + + OrthancPluginErrorCode (*tagMostRecentPatient) ( + /* inputs */ + void* payload, + int64_t patientId); + + + /** + * Extensions since Orthanc 1.5.4 + **/ + + /* Ouput: Use OrthancPluginDatabaseAnswerMetadata */ + OrthancPluginErrorCode (*getAllMetadata) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + /* inputs */ + void* payload, + int64_t resourceId); + + /* Ouput: Use OrthancPluginDatabaseAnswerString to send + the public ID of the parent (if the resource is not a patient) */ + OrthancPluginErrorCode (*lookupResourceAndParent) ( + /* outputs */ + OrthancPluginDatabaseContext* context, + uint8_t* isExisting, + int64_t* id, + OrthancPluginResourceType* type, + + /* inputs */ + void* payload, + const char* publicId); + + } OrthancPluginDatabaseExtensions; + +/*InvokeService(context, _OrthancPluginService_RegisterDatabaseBackend, ¶ms) || + result == NULL) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + typedef struct + { + OrthancPluginDatabaseContext** result; + const OrthancPluginDatabaseBackend* backend; + void* payload; + const OrthancPluginDatabaseExtensions* extensions; + uint32_t extensionsSize; + } _OrthancPluginRegisterDatabaseBackendV2; + + + /** + * Register a custom database back-end. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param backend The callbacks of the custom database engine. + * @param payload Pointer containing private information for the database engine. + * @param extensions Extensions to the base database SDK that was shipped until Orthanc 0.9.3. + * @return The context of the database engine (it must not be manually freed). + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginDatabaseContext* OrthancPluginRegisterDatabaseBackendV2( + OrthancPluginContext* context, + const OrthancPluginDatabaseBackend* backend, + const OrthancPluginDatabaseExtensions* extensions, + void* payload) + { + OrthancPluginDatabaseContext* result = NULL; + _OrthancPluginRegisterDatabaseBackendV2 params; + + if (sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType)) + { + return NULL; + } + + memset(¶ms, 0, sizeof(params)); + params.backend = backend; + params.result = &result; + params.payload = payload; + params.extensions = extensions; + params.extensionsSize = sizeof(OrthancPluginDatabaseExtensions); + + if (context->InvokeService(context, _OrthancPluginService_RegisterDatabaseBackendV2, ¶ms) || + result == NULL) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + +#ifdef __cplusplus +} +#endif + + +/** @} */ + diff -Nru orthanc-mysql-2.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h orthanc-mysql-3.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h --- orthanc-mysql-2.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,6802 @@ +/** + * \mainpage + * + * This C/C++ SDK allows external developers to create plugins that + * can be loaded into Orthanc to extend its functionality. Each + * Orthanc plugin must expose 4 public functions with the following + * signatures: + * + * -# int32_t OrthancPluginInitialize(const OrthancPluginContext* context): + * This function is invoked by Orthanc when it loads the plugin on startup. + * The plugin must: + * - Check its compatibility with the Orthanc version using + * ::OrthancPluginCheckVersion(). + * - Store the context pointer so that it can use the plugin + * services of Orthanc. + * - Register all its REST callbacks using ::OrthancPluginRegisterRestCallback(). + * - Possibly register its callback for received DICOM instances using ::OrthancPluginRegisterOnStoredInstanceCallback(). + * - Possibly register its callback for changes to the DICOM store using ::OrthancPluginRegisterOnChangeCallback(). + * - Possibly register a custom storage area using ::OrthancPluginRegisterStorageArea(). + * - Possibly register a custom database back-end area using OrthancPluginRegisterDatabaseBackendV2(). + * - Possibly register a handler for C-Find SCP using OrthancPluginRegisterFindCallback(). + * - Possibly register a handler for C-Find SCP against DICOM worklists using OrthancPluginRegisterWorklistCallback(). + * - Possibly register a handler for C-Move SCP using OrthancPluginRegisterMoveCallback(). + * - Possibly register a custom decoder for DICOM images using OrthancPluginRegisterDecodeImageCallback(). + * - Possibly register a callback to filter incoming HTTP requests using OrthancPluginRegisterIncomingHttpRequestFilter2(). + * - Possibly register a callback to unserialize jobs using OrthancPluginRegisterJobsUnserializer(). + * - Possibly register a callback to refresh its metrics using OrthancPluginRegisterRefreshMetricsCallback(). + * -# void OrthancPluginFinalize(): + * This function is invoked by Orthanc during its shutdown. The plugin + * must free all its memory. + * -# const char* OrthancPluginGetName(): + * The plugin must return a short string to identify itself. + * -# const char* OrthancPluginGetVersion(): + * The plugin must return a string containing its version number. + * + * The name and the version of a plugin is only used to prevent it + * from being loaded twice. Note that, in C++, it is mandatory to + * declare these functions within an extern "C" section. + * + * To ensure multi-threading safety, the various REST callbacks are + * guaranteed to be executed in mutual exclusion since Orthanc + * 0.8.5. If this feature is undesired (notably when developing + * high-performance plugins handling simultaneous requests), use + * ::OrthancPluginRegisterRestCallbackNoLock(). + **/ + + + +/** + * @defgroup Images Images and compression + * @brief Functions to deal with images and compressed buffers. + * + * @defgroup REST REST + * @brief Functions to answer REST requests in a callback. + * + * @defgroup Callbacks Callbacks + * @brief Functions to register and manage callbacks by the plugins. + * + * @defgroup DicomCallbacks DicomCallbacks + * @brief Functions to register and manage DICOM callbacks (worklists, C-Find, C-MOVE). + * + * @defgroup Orthanc Orthanc + * @brief Functions to access the content of the Orthanc server. + **/ + + + +/** + * @defgroup Toolbox Toolbox + * @brief Generic functions to help with the creation of plugins. + **/ + + + +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + + +#pragma once + + +#include +#include + +#ifdef WIN32 +#define ORTHANC_PLUGINS_API __declspec(dllexport) +#else +#define ORTHANC_PLUGINS_API +#endif + +#define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER 1 +#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 5 +#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 4 + + +#if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) +#define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \ + (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \ + (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \ + (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \ + (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \ + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision)))) +#endif + + + +/******************************************************************** + ** Check that function inlining is properly supported. The use of + ** inlining is required, to avoid the duplication of object code + ** between two compilation modules that would use the Orthanc Plugin + ** API. + ********************************************************************/ + +/* If the auto-detection of the "inline" keyword below does not work + automatically and that your compiler is known to properly support + inlining, uncomment the following #define and adapt the definition + of "static inline". */ + +/* #define ORTHANC_PLUGIN_INLINE static inline */ + +#ifndef ORTHANC_PLUGIN_INLINE +# if __STDC_VERSION__ >= 199901L +/* This is C99 or above: http://predef.sourceforge.net/prestd.html */ +# define ORTHANC_PLUGIN_INLINE static inline +# elif defined(__cplusplus) +/* This is C++ */ +# define ORTHANC_PLUGIN_INLINE static inline +# elif defined(__GNUC__) +/* This is GCC running in C89 mode */ +# define ORTHANC_PLUGIN_INLINE static __inline +# elif defined(_MSC_VER) +/* This is Visual Studio running in C89 mode */ +# define ORTHANC_PLUGIN_INLINE static __inline +# else +# error Your compiler is not known to support the "inline" keyword +# endif +#endif + + + +/******************************************************************** + ** Inclusion of standard libraries. + ********************************************************************/ + +/** + * For Microsoft Visual Studio, a compatibility "stdint.h" can be + * downloaded at the following URL: + * https://orthanc.googlecode.com/hg/Resources/ThirdParty/VisualStudio/stdint.h + **/ +#include + +#include + + + +/******************************************************************** + ** Definition of the Orthanc Plugin API. + ********************************************************************/ + +/** @{ */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * The various error codes that can be returned by the Orthanc core. + **/ + typedef enum + { + OrthancPluginErrorCode_InternalError = -1 /*!< Internal error */, + OrthancPluginErrorCode_Success = 0 /*!< Success */, + OrthancPluginErrorCode_Plugin = 1 /*!< Error encountered within the plugin engine */, + OrthancPluginErrorCode_NotImplemented = 2 /*!< Not implemented yet */, + OrthancPluginErrorCode_ParameterOutOfRange = 3 /*!< Parameter out of range */, + OrthancPluginErrorCode_NotEnoughMemory = 4 /*!< The server hosting Orthanc is running out of memory */, + OrthancPluginErrorCode_BadParameterType = 5 /*!< Bad type for a parameter */, + OrthancPluginErrorCode_BadSequenceOfCalls = 6 /*!< Bad sequence of calls */, + OrthancPluginErrorCode_InexistentItem = 7 /*!< Accessing an inexistent item */, + OrthancPluginErrorCode_BadRequest = 8 /*!< Bad request */, + OrthancPluginErrorCode_NetworkProtocol = 9 /*!< Error in the network protocol */, + OrthancPluginErrorCode_SystemCommand = 10 /*!< Error while calling a system command */, + OrthancPluginErrorCode_Database = 11 /*!< Error with the database engine */, + OrthancPluginErrorCode_UriSyntax = 12 /*!< Badly formatted URI */, + OrthancPluginErrorCode_InexistentFile = 13 /*!< Inexistent file */, + OrthancPluginErrorCode_CannotWriteFile = 14 /*!< Cannot write to file */, + OrthancPluginErrorCode_BadFileFormat = 15 /*!< Bad file format */, + OrthancPluginErrorCode_Timeout = 16 /*!< Timeout */, + OrthancPluginErrorCode_UnknownResource = 17 /*!< Unknown resource */, + OrthancPluginErrorCode_IncompatibleDatabaseVersion = 18 /*!< Incompatible version of the database */, + OrthancPluginErrorCode_FullStorage = 19 /*!< The file storage is full */, + OrthancPluginErrorCode_CorruptedFile = 20 /*!< Corrupted file (e.g. inconsistent MD5 hash) */, + OrthancPluginErrorCode_InexistentTag = 21 /*!< Inexistent tag */, + OrthancPluginErrorCode_ReadOnly = 22 /*!< Cannot modify a read-only data structure */, + OrthancPluginErrorCode_IncompatibleImageFormat = 23 /*!< Incompatible format of the images */, + OrthancPluginErrorCode_IncompatibleImageSize = 24 /*!< Incompatible size of the images */, + OrthancPluginErrorCode_SharedLibrary = 25 /*!< Error while using a shared library (plugin) */, + OrthancPluginErrorCode_UnknownPluginService = 26 /*!< Plugin invoking an unknown service */, + OrthancPluginErrorCode_UnknownDicomTag = 27 /*!< Unknown DICOM tag */, + OrthancPluginErrorCode_BadJson = 28 /*!< Cannot parse a JSON document */, + OrthancPluginErrorCode_Unauthorized = 29 /*!< Bad credentials were provided to an HTTP request */, + OrthancPluginErrorCode_BadFont = 30 /*!< Badly formatted font file */, + OrthancPluginErrorCode_DatabasePlugin = 31 /*!< The plugin implementing a custom database back-end does not fulfill the proper interface */, + OrthancPluginErrorCode_StorageAreaPlugin = 32 /*!< Error in the plugin implementing a custom storage area */, + OrthancPluginErrorCode_EmptyRequest = 33 /*!< The request is empty */, + OrthancPluginErrorCode_NotAcceptable = 34 /*!< Cannot send a response which is acceptable according to the Accept HTTP header */, + OrthancPluginErrorCode_NullPointer = 35 /*!< Cannot handle a NULL pointer */, + OrthancPluginErrorCode_DatabaseUnavailable = 36 /*!< The database is currently not available (probably a transient situation) */, + OrthancPluginErrorCode_CanceledJob = 37 /*!< This job was canceled */, + OrthancPluginErrorCode_SQLiteNotOpened = 1000 /*!< SQLite: The database is not opened */, + OrthancPluginErrorCode_SQLiteAlreadyOpened = 1001 /*!< SQLite: Connection is already open */, + OrthancPluginErrorCode_SQLiteCannotOpen = 1002 /*!< SQLite: Unable to open the database */, + OrthancPluginErrorCode_SQLiteStatementAlreadyUsed = 1003 /*!< SQLite: This cached statement is already being referred to */, + OrthancPluginErrorCode_SQLiteExecute = 1004 /*!< SQLite: Cannot execute a command */, + OrthancPluginErrorCode_SQLiteRollbackWithoutTransaction = 1005 /*!< SQLite: Rolling back a nonexistent transaction (have you called Begin()?) */, + OrthancPluginErrorCode_SQLiteCommitWithoutTransaction = 1006 /*!< SQLite: Committing a nonexistent transaction */, + OrthancPluginErrorCode_SQLiteRegisterFunction = 1007 /*!< SQLite: Unable to register a function */, + OrthancPluginErrorCode_SQLiteFlush = 1008 /*!< SQLite: Unable to flush the database */, + OrthancPluginErrorCode_SQLiteCannotRun = 1009 /*!< SQLite: Cannot run a cached statement */, + OrthancPluginErrorCode_SQLiteCannotStep = 1010 /*!< SQLite: Cannot step over a cached statement */, + OrthancPluginErrorCode_SQLiteBindOutOfRange = 1011 /*!< SQLite: Bing a value while out of range (serious error) */, + OrthancPluginErrorCode_SQLitePrepareStatement = 1012 /*!< SQLite: Cannot prepare a cached statement */, + OrthancPluginErrorCode_SQLiteTransactionAlreadyStarted = 1013 /*!< SQLite: Beginning the same transaction twice */, + OrthancPluginErrorCode_SQLiteTransactionCommit = 1014 /*!< SQLite: Failure when committing the transaction */, + OrthancPluginErrorCode_SQLiteTransactionBegin = 1015 /*!< SQLite: Cannot start a transaction */, + OrthancPluginErrorCode_DirectoryOverFile = 2000 /*!< The directory to be created is already occupied by a regular file */, + OrthancPluginErrorCode_FileStorageCannotWrite = 2001 /*!< Unable to create a subdirectory or a file in the file storage */, + OrthancPluginErrorCode_DirectoryExpected = 2002 /*!< The specified path does not point to a directory */, + OrthancPluginErrorCode_HttpPortInUse = 2003 /*!< The TCP port of the HTTP server is privileged or already in use */, + OrthancPluginErrorCode_DicomPortInUse = 2004 /*!< The TCP port of the DICOM server is privileged or already in use */, + OrthancPluginErrorCode_BadHttpStatusInRest = 2005 /*!< This HTTP status is not allowed in a REST API */, + OrthancPluginErrorCode_RegularFileExpected = 2006 /*!< The specified path does not point to a regular file */, + OrthancPluginErrorCode_PathToExecutable = 2007 /*!< Unable to get the path to the executable */, + OrthancPluginErrorCode_MakeDirectory = 2008 /*!< Cannot create a directory */, + OrthancPluginErrorCode_BadApplicationEntityTitle = 2009 /*!< An application entity title (AET) cannot be empty or be longer than 16 characters */, + OrthancPluginErrorCode_NoCFindHandler = 2010 /*!< No request handler factory for DICOM C-FIND SCP */, + OrthancPluginErrorCode_NoCMoveHandler = 2011 /*!< No request handler factory for DICOM C-MOVE SCP */, + OrthancPluginErrorCode_NoCStoreHandler = 2012 /*!< No request handler factory for DICOM C-STORE SCP */, + OrthancPluginErrorCode_NoApplicationEntityFilter = 2013 /*!< No application entity filter */, + OrthancPluginErrorCode_NoSopClassOrInstance = 2014 /*!< DicomUserConnection: Unable to find the SOP class and instance */, + OrthancPluginErrorCode_NoPresentationContext = 2015 /*!< DicomUserConnection: No acceptable presentation context for modality */, + OrthancPluginErrorCode_DicomFindUnavailable = 2016 /*!< DicomUserConnection: The C-FIND command is not supported by the remote SCP */, + OrthancPluginErrorCode_DicomMoveUnavailable = 2017 /*!< DicomUserConnection: The C-MOVE command is not supported by the remote SCP */, + OrthancPluginErrorCode_CannotStoreInstance = 2018 /*!< Cannot store an instance */, + OrthancPluginErrorCode_CreateDicomNotString = 2019 /*!< Only string values are supported when creating DICOM instances */, + OrthancPluginErrorCode_CreateDicomOverrideTag = 2020 /*!< Trying to override a value inherited from a parent module */, + OrthancPluginErrorCode_CreateDicomUseContent = 2021 /*!< Use \"Content\" to inject an image into a new DICOM instance */, + OrthancPluginErrorCode_CreateDicomNoPayload = 2022 /*!< No payload is present for one instance in the series */, + OrthancPluginErrorCode_CreateDicomUseDataUriScheme = 2023 /*!< The payload of the DICOM instance must be specified according to Data URI scheme */, + OrthancPluginErrorCode_CreateDicomBadParent = 2024 /*!< Trying to attach a new DICOM instance to an inexistent resource */, + OrthancPluginErrorCode_CreateDicomParentIsInstance = 2025 /*!< Trying to attach a new DICOM instance to an instance (must be a series, study or patient) */, + OrthancPluginErrorCode_CreateDicomParentEncoding = 2026 /*!< Unable to get the encoding of the parent resource */, + OrthancPluginErrorCode_UnknownModality = 2027 /*!< Unknown modality */, + OrthancPluginErrorCode_BadJobOrdering = 2028 /*!< Bad ordering of filters in a job */, + OrthancPluginErrorCode_JsonToLuaTable = 2029 /*!< Cannot convert the given JSON object to a Lua table */, + OrthancPluginErrorCode_CannotCreateLua = 2030 /*!< Cannot create the Lua context */, + OrthancPluginErrorCode_CannotExecuteLua = 2031 /*!< Cannot execute a Lua command */, + OrthancPluginErrorCode_LuaAlreadyExecuted = 2032 /*!< Arguments cannot be pushed after the Lua function is executed */, + OrthancPluginErrorCode_LuaBadOutput = 2033 /*!< The Lua function does not give the expected number of outputs */, + OrthancPluginErrorCode_NotLuaPredicate = 2034 /*!< The Lua function is not a predicate (only true/false outputs allowed) */, + OrthancPluginErrorCode_LuaReturnsNoString = 2035 /*!< The Lua function does not return a string */, + OrthancPluginErrorCode_StorageAreaAlreadyRegistered = 2036 /*!< Another plugin has already registered a custom storage area */, + OrthancPluginErrorCode_DatabaseBackendAlreadyRegistered = 2037 /*!< Another plugin has already registered a custom database back-end */, + OrthancPluginErrorCode_DatabaseNotInitialized = 2038 /*!< Plugin trying to call the database during its initialization */, + OrthancPluginErrorCode_SslDisabled = 2039 /*!< Orthanc has been built without SSL support */, + OrthancPluginErrorCode_CannotOrderSlices = 2040 /*!< Unable to order the slices of the series */, + OrthancPluginErrorCode_NoWorklistHandler = 2041 /*!< No request handler factory for DICOM C-Find Modality SCP */, + OrthancPluginErrorCode_AlreadyExistingTag = 2042 /*!< Cannot override the value of a tag that already exists */, + + _OrthancPluginErrorCode_INTERNAL = 0x7fffffff + } OrthancPluginErrorCode; + + + /** + * Forward declaration of one of the mandatory functions for Orthanc + * plugins. + **/ + ORTHANC_PLUGINS_API const char* OrthancPluginGetName(); + + + /** + * The various HTTP methods for a REST call. + **/ + typedef enum + { + OrthancPluginHttpMethod_Get = 1, /*!< GET request */ + OrthancPluginHttpMethod_Post = 2, /*!< POST request */ + OrthancPluginHttpMethod_Put = 3, /*!< PUT request */ + OrthancPluginHttpMethod_Delete = 4, /*!< DELETE request */ + + _OrthancPluginHttpMethod_INTERNAL = 0x7fffffff + } OrthancPluginHttpMethod; + + + /** + * @brief The parameters of a REST request. + * @ingroup Callbacks + **/ + typedef struct + { + /** + * @brief The HTTP method. + **/ + OrthancPluginHttpMethod method; + + /** + * @brief The number of groups of the regular expression. + **/ + uint32_t groupsCount; + + /** + * @brief The matched values for the groups of the regular expression. + **/ + const char* const* groups; + + /** + * @brief For a GET request, the number of GET parameters. + **/ + uint32_t getCount; + + /** + * @brief For a GET request, the keys of the GET parameters. + **/ + const char* const* getKeys; + + /** + * @brief For a GET request, the values of the GET parameters. + **/ + const char* const* getValues; + + /** + * @brief For a PUT or POST request, the content of the body. + **/ + const char* body; + + /** + * @brief For a PUT or POST request, the number of bytes of the body. + **/ + uint32_t bodySize; + + + /* -------------------------------------------------- + New in version 0.8.1 + -------------------------------------------------- */ + + /** + * @brief The number of HTTP headers. + **/ + uint32_t headersCount; + + /** + * @brief The keys of the HTTP headers (always converted to low-case). + **/ + const char* const* headersKeys; + + /** + * @brief The values of the HTTP headers. + **/ + const char* const* headersValues; + + } OrthancPluginHttpRequest; + + + typedef enum + { + /* Generic services */ + _OrthancPluginService_LogInfo = 1, + _OrthancPluginService_LogWarning = 2, + _OrthancPluginService_LogError = 3, + _OrthancPluginService_GetOrthancPath = 4, + _OrthancPluginService_GetOrthancDirectory = 5, + _OrthancPluginService_GetConfigurationPath = 6, + _OrthancPluginService_SetPluginProperty = 7, + _OrthancPluginService_GetGlobalProperty = 8, + _OrthancPluginService_SetGlobalProperty = 9, + _OrthancPluginService_GetCommandLineArgumentsCount = 10, + _OrthancPluginService_GetCommandLineArgument = 11, + _OrthancPluginService_GetExpectedDatabaseVersion = 12, + _OrthancPluginService_GetConfiguration = 13, + _OrthancPluginService_BufferCompression = 14, + _OrthancPluginService_ReadFile = 15, + _OrthancPluginService_WriteFile = 16, + _OrthancPluginService_GetErrorDescription = 17, + _OrthancPluginService_CallHttpClient = 18, + _OrthancPluginService_RegisterErrorCode = 19, + _OrthancPluginService_RegisterDictionaryTag = 20, + _OrthancPluginService_DicomBufferToJson = 21, + _OrthancPluginService_DicomInstanceToJson = 22, + _OrthancPluginService_CreateDicom = 23, + _OrthancPluginService_ComputeMd5 = 24, + _OrthancPluginService_ComputeSha1 = 25, + _OrthancPluginService_LookupDictionary = 26, + _OrthancPluginService_CallHttpClient2 = 27, + _OrthancPluginService_GenerateUuid = 28, + _OrthancPluginService_RegisterPrivateDictionaryTag = 29, + _OrthancPluginService_AutodetectMimeType = 30, + _OrthancPluginService_SetMetricsValue = 31, + _OrthancPluginService_EncodeDicomWebJson = 32, + _OrthancPluginService_EncodeDicomWebXml = 33, + + /* Registration of callbacks */ + _OrthancPluginService_RegisterRestCallback = 1000, + _OrthancPluginService_RegisterOnStoredInstanceCallback = 1001, + _OrthancPluginService_RegisterStorageArea = 1002, + _OrthancPluginService_RegisterOnChangeCallback = 1003, + _OrthancPluginService_RegisterRestCallbackNoLock = 1004, + _OrthancPluginService_RegisterWorklistCallback = 1005, + _OrthancPluginService_RegisterDecodeImageCallback = 1006, + _OrthancPluginService_RegisterIncomingHttpRequestFilter = 1007, + _OrthancPluginService_RegisterFindCallback = 1008, + _OrthancPluginService_RegisterMoveCallback = 1009, + _OrthancPluginService_RegisterIncomingHttpRequestFilter2 = 1010, + _OrthancPluginService_RegisterRefreshMetricsCallback = 1011, + + /* Sending answers to REST calls */ + _OrthancPluginService_AnswerBuffer = 2000, + _OrthancPluginService_CompressAndAnswerPngImage = 2001, /* Unused as of Orthanc 0.9.4 */ + _OrthancPluginService_Redirect = 2002, + _OrthancPluginService_SendHttpStatusCode = 2003, + _OrthancPluginService_SendUnauthorized = 2004, + _OrthancPluginService_SendMethodNotAllowed = 2005, + _OrthancPluginService_SetCookie = 2006, + _OrthancPluginService_SetHttpHeader = 2007, + _OrthancPluginService_StartMultipartAnswer = 2008, + _OrthancPluginService_SendMultipartItem = 2009, + _OrthancPluginService_SendHttpStatus = 2010, + _OrthancPluginService_CompressAndAnswerImage = 2011, + _OrthancPluginService_SendMultipartItem2 = 2012, + _OrthancPluginService_SetHttpErrorDetails = 2013, + + /* Access to the Orthanc database and API */ + _OrthancPluginService_GetDicomForInstance = 3000, + _OrthancPluginService_RestApiGet = 3001, + _OrthancPluginService_RestApiPost = 3002, + _OrthancPluginService_RestApiDelete = 3003, + _OrthancPluginService_RestApiPut = 3004, + _OrthancPluginService_LookupPatient = 3005, + _OrthancPluginService_LookupStudy = 3006, + _OrthancPluginService_LookupSeries = 3007, + _OrthancPluginService_LookupInstance = 3008, + _OrthancPluginService_LookupStudyWithAccessionNumber = 3009, + _OrthancPluginService_RestApiGetAfterPlugins = 3010, + _OrthancPluginService_RestApiPostAfterPlugins = 3011, + _OrthancPluginService_RestApiDeleteAfterPlugins = 3012, + _OrthancPluginService_RestApiPutAfterPlugins = 3013, + _OrthancPluginService_ReconstructMainDicomTags = 3014, + _OrthancPluginService_RestApiGet2 = 3015, + + /* Access to DICOM instances */ + _OrthancPluginService_GetInstanceRemoteAet = 4000, + _OrthancPluginService_GetInstanceSize = 4001, + _OrthancPluginService_GetInstanceData = 4002, + _OrthancPluginService_GetInstanceJson = 4003, + _OrthancPluginService_GetInstanceSimplifiedJson = 4004, + _OrthancPluginService_HasInstanceMetadata = 4005, + _OrthancPluginService_GetInstanceMetadata = 4006, + _OrthancPluginService_GetInstanceOrigin = 4007, + + /* Services for plugins implementing a database back-end */ + _OrthancPluginService_RegisterDatabaseBackend = 5000, + _OrthancPluginService_DatabaseAnswer = 5001, + _OrthancPluginService_RegisterDatabaseBackendV2 = 5002, + _OrthancPluginService_StorageAreaCreate = 5003, + _OrthancPluginService_StorageAreaRead = 5004, + _OrthancPluginService_StorageAreaRemove = 5005, + + /* Primitives for handling images */ + _OrthancPluginService_GetImagePixelFormat = 6000, + _OrthancPluginService_GetImageWidth = 6001, + _OrthancPluginService_GetImageHeight = 6002, + _OrthancPluginService_GetImagePitch = 6003, + _OrthancPluginService_GetImageBuffer = 6004, + _OrthancPluginService_UncompressImage = 6005, + _OrthancPluginService_FreeImage = 6006, + _OrthancPluginService_CompressImage = 6007, + _OrthancPluginService_ConvertPixelFormat = 6008, + _OrthancPluginService_GetFontsCount = 6009, + _OrthancPluginService_GetFontInfo = 6010, + _OrthancPluginService_DrawText = 6011, + _OrthancPluginService_CreateImage = 6012, + _OrthancPluginService_CreateImageAccessor = 6013, + _OrthancPluginService_DecodeDicomImage = 6014, + + /* Primitives for handling C-Find, C-Move and worklists */ + _OrthancPluginService_WorklistAddAnswer = 7000, + _OrthancPluginService_WorklistMarkIncomplete = 7001, + _OrthancPluginService_WorklistIsMatch = 7002, + _OrthancPluginService_WorklistGetDicomQuery = 7003, + _OrthancPluginService_FindAddAnswer = 7004, + _OrthancPluginService_FindMarkIncomplete = 7005, + _OrthancPluginService_GetFindQuerySize = 7006, + _OrthancPluginService_GetFindQueryTag = 7007, + _OrthancPluginService_GetFindQueryTagName = 7008, + _OrthancPluginService_GetFindQueryValue = 7009, + _OrthancPluginService_CreateFindMatcher = 7010, + _OrthancPluginService_FreeFindMatcher = 7011, + _OrthancPluginService_FindMatcherIsMatch = 7012, + + /* Primitives for accessing Orthanc Peers (new in 1.4.2) */ + _OrthancPluginService_GetPeers = 8000, + _OrthancPluginService_FreePeers = 8001, + _OrthancPluginService_GetPeersCount = 8003, + _OrthancPluginService_GetPeerName = 8004, + _OrthancPluginService_GetPeerUrl = 8005, + _OrthancPluginService_CallPeerApi = 8006, + _OrthancPluginService_GetPeerUserProperty = 8007, + + /* Primitives for handling jobs (new in 1.4.2) */ + _OrthancPluginService_CreateJob = 9000, + _OrthancPluginService_FreeJob = 9001, + _OrthancPluginService_SubmitJob = 9002, + _OrthancPluginService_RegisterJobsUnserializer = 9003, + + _OrthancPluginService_INTERNAL = 0x7fffffff + } _OrthancPluginService; + + + typedef enum + { + _OrthancPluginProperty_Description = 1, + _OrthancPluginProperty_RootUri = 2, + _OrthancPluginProperty_OrthancExplorer = 3, + + _OrthancPluginProperty_INTERNAL = 0x7fffffff + } _OrthancPluginProperty; + + + + /** + * The memory layout of the pixels of an image. + * @ingroup Images + **/ + typedef enum + { + /** + * @brief Graylevel 8bpp image. + * + * The image is graylevel. Each pixel is unsigned and stored in + * one byte. + **/ + OrthancPluginPixelFormat_Grayscale8 = 1, + + /** + * @brief Graylevel, unsigned 16bpp image. + * + * The image is graylevel. Each pixel is unsigned and stored in + * two bytes. + **/ + OrthancPluginPixelFormat_Grayscale16 = 2, + + /** + * @brief Graylevel, signed 16bpp image. + * + * The image is graylevel. Each pixel is signed and stored in two + * bytes. + **/ + OrthancPluginPixelFormat_SignedGrayscale16 = 3, + + /** + * @brief Color image in RGB24 format. + * + * This format describes a color image. The pixels are stored in 3 + * consecutive bytes. The memory layout is RGB. + **/ + OrthancPluginPixelFormat_RGB24 = 4, + + /** + * @brief Color image in RGBA32 format. + * + * This format describes a color image. The pixels are stored in 4 + * consecutive bytes. The memory layout is RGBA. + **/ + OrthancPluginPixelFormat_RGBA32 = 5, + + OrthancPluginPixelFormat_Unknown = 6, /*!< Unknown pixel format */ + + /** + * @brief Color image in RGB48 format. + * + * This format describes a color image. The pixels are stored in 6 + * consecutive bytes. The memory layout is RRGGBB. + **/ + OrthancPluginPixelFormat_RGB48 = 7, + + /** + * @brief Graylevel, unsigned 32bpp image. + * + * The image is graylevel. Each pixel is unsigned and stored in + * four bytes. + **/ + OrthancPluginPixelFormat_Grayscale32 = 8, + + /** + * @brief Graylevel, floating-point 32bpp image. + * + * The image is graylevel. Each pixel is floating-point and stored + * in four bytes. + **/ + OrthancPluginPixelFormat_Float32 = 9, + + /** + * @brief Color image in BGRA32 format. + * + * This format describes a color image. The pixels are stored in 4 + * consecutive bytes. The memory layout is BGRA. + **/ + OrthancPluginPixelFormat_BGRA32 = 10, + + /** + * @brief Graylevel, unsigned 64bpp image. + * + * The image is graylevel. Each pixel is unsigned and stored in + * eight bytes. + **/ + OrthancPluginPixelFormat_Grayscale64 = 11, + + _OrthancPluginPixelFormat_INTERNAL = 0x7fffffff + } OrthancPluginPixelFormat; + + + + /** + * The content types that are supported by Orthanc plugins. + **/ + typedef enum + { + OrthancPluginContentType_Unknown = 0, /*!< Unknown content type */ + OrthancPluginContentType_Dicom = 1, /*!< DICOM */ + OrthancPluginContentType_DicomAsJson = 2, /*!< JSON summary of a DICOM file */ + + _OrthancPluginContentType_INTERNAL = 0x7fffffff + } OrthancPluginContentType; + + + + /** + * The supported types of DICOM resources. + **/ + typedef enum + { + OrthancPluginResourceType_Patient = 0, /*!< Patient */ + OrthancPluginResourceType_Study = 1, /*!< Study */ + OrthancPluginResourceType_Series = 2, /*!< Series */ + OrthancPluginResourceType_Instance = 3, /*!< Instance */ + OrthancPluginResourceType_None = 4, /*!< Unavailable resource type */ + + _OrthancPluginResourceType_INTERNAL = 0x7fffffff + } OrthancPluginResourceType; + + + + /** + * The supported types of changes that can happen to DICOM resources. + * @ingroup Callbacks + **/ + typedef enum + { + OrthancPluginChangeType_CompletedSeries = 0, /*!< Series is now complete */ + OrthancPluginChangeType_Deleted = 1, /*!< Deleted resource */ + OrthancPluginChangeType_NewChildInstance = 2, /*!< A new instance was added to this resource */ + OrthancPluginChangeType_NewInstance = 3, /*!< New instance received */ + OrthancPluginChangeType_NewPatient = 4, /*!< New patient created */ + OrthancPluginChangeType_NewSeries = 5, /*!< New series created */ + OrthancPluginChangeType_NewStudy = 6, /*!< New study created */ + OrthancPluginChangeType_StablePatient = 7, /*!< Timeout: No new instance in this patient */ + OrthancPluginChangeType_StableSeries = 8, /*!< Timeout: No new instance in this series */ + OrthancPluginChangeType_StableStudy = 9, /*!< Timeout: No new instance in this study */ + OrthancPluginChangeType_OrthancStarted = 10, /*!< Orthanc has started */ + OrthancPluginChangeType_OrthancStopped = 11, /*!< Orthanc is stopping */ + OrthancPluginChangeType_UpdatedAttachment = 12, /*!< Some user-defined attachment has changed for this resource */ + OrthancPluginChangeType_UpdatedMetadata = 13, /*!< Some user-defined metadata has changed for this resource */ + OrthancPluginChangeType_UpdatedPeers = 14, /*!< The list of Orthanc peers has changed */ + OrthancPluginChangeType_UpdatedModalities = 15, /*!< The list of DICOM modalities has changed */ + + _OrthancPluginChangeType_INTERNAL = 0x7fffffff + } OrthancPluginChangeType; + + + /** + * The compression algorithms that are supported by the Orthanc core. + * @ingroup Images + **/ + typedef enum + { + OrthancPluginCompressionType_Zlib = 0, /*!< Standard zlib compression */ + OrthancPluginCompressionType_ZlibWithSize = 1, /*!< zlib, prefixed with uncompressed size (uint64_t) */ + OrthancPluginCompressionType_Gzip = 2, /*!< Standard gzip compression */ + OrthancPluginCompressionType_GzipWithSize = 3, /*!< gzip, prefixed with uncompressed size (uint64_t) */ + + _OrthancPluginCompressionType_INTERNAL = 0x7fffffff + } OrthancPluginCompressionType; + + + /** + * The image formats that are supported by the Orthanc core. + * @ingroup Images + **/ + typedef enum + { + OrthancPluginImageFormat_Png = 0, /*!< Image compressed using PNG */ + OrthancPluginImageFormat_Jpeg = 1, /*!< Image compressed using JPEG */ + OrthancPluginImageFormat_Dicom = 2, /*!< Image compressed using DICOM */ + + _OrthancPluginImageFormat_INTERNAL = 0x7fffffff + } OrthancPluginImageFormat; + + + /** + * The value representations present in the DICOM standard (version 2013). + * @ingroup Toolbox + **/ + typedef enum + { + OrthancPluginValueRepresentation_AE = 1, /*!< Application Entity */ + OrthancPluginValueRepresentation_AS = 2, /*!< Age String */ + OrthancPluginValueRepresentation_AT = 3, /*!< Attribute Tag */ + OrthancPluginValueRepresentation_CS = 4, /*!< Code String */ + OrthancPluginValueRepresentation_DA = 5, /*!< Date */ + OrthancPluginValueRepresentation_DS = 6, /*!< Decimal String */ + OrthancPluginValueRepresentation_DT = 7, /*!< Date Time */ + OrthancPluginValueRepresentation_FD = 8, /*!< Floating Point Double */ + OrthancPluginValueRepresentation_FL = 9, /*!< Floating Point Single */ + OrthancPluginValueRepresentation_IS = 10, /*!< Integer String */ + OrthancPluginValueRepresentation_LO = 11, /*!< Long String */ + OrthancPluginValueRepresentation_LT = 12, /*!< Long Text */ + OrthancPluginValueRepresentation_OB = 13, /*!< Other Byte String */ + OrthancPluginValueRepresentation_OF = 14, /*!< Other Float String */ + OrthancPluginValueRepresentation_OW = 15, /*!< Other Word String */ + OrthancPluginValueRepresentation_PN = 16, /*!< Person Name */ + OrthancPluginValueRepresentation_SH = 17, /*!< Short String */ + OrthancPluginValueRepresentation_SL = 18, /*!< Signed Long */ + OrthancPluginValueRepresentation_SQ = 19, /*!< Sequence of Items */ + OrthancPluginValueRepresentation_SS = 20, /*!< Signed Short */ + OrthancPluginValueRepresentation_ST = 21, /*!< Short Text */ + OrthancPluginValueRepresentation_TM = 22, /*!< Time */ + OrthancPluginValueRepresentation_UI = 23, /*!< Unique Identifier (UID) */ + OrthancPluginValueRepresentation_UL = 24, /*!< Unsigned Long */ + OrthancPluginValueRepresentation_UN = 25, /*!< Unknown */ + OrthancPluginValueRepresentation_US = 26, /*!< Unsigned Short */ + OrthancPluginValueRepresentation_UT = 27, /*!< Unlimited Text */ + + _OrthancPluginValueRepresentation_INTERNAL = 0x7fffffff + } OrthancPluginValueRepresentation; + + + /** + * The possible output formats for a DICOM-to-JSON conversion. + * @ingroup Toolbox + * @see OrthancPluginDicomToJson() + **/ + typedef enum + { + OrthancPluginDicomToJsonFormat_Full = 1, /*!< Full output, with most details */ + OrthancPluginDicomToJsonFormat_Short = 2, /*!< Tags output as hexadecimal numbers */ + OrthancPluginDicomToJsonFormat_Human = 3, /*!< Human-readable JSON */ + + _OrthancPluginDicomToJsonFormat_INTERNAL = 0x7fffffff + } OrthancPluginDicomToJsonFormat; + + + /** + * Flags to customize a DICOM-to-JSON conversion. By default, binary + * tags are formatted using Data URI scheme. + * @ingroup Toolbox + **/ + typedef enum + { + OrthancPluginDicomToJsonFlags_None = 0, + OrthancPluginDicomToJsonFlags_IncludeBinary = (1 << 0), /*!< Include the binary tags */ + OrthancPluginDicomToJsonFlags_IncludePrivateTags = (1 << 1), /*!< Include the private tags */ + OrthancPluginDicomToJsonFlags_IncludeUnknownTags = (1 << 2), /*!< Include the tags unknown by the dictionary */ + OrthancPluginDicomToJsonFlags_IncludePixelData = (1 << 3), /*!< Include the pixel data */ + OrthancPluginDicomToJsonFlags_ConvertBinaryToAscii = (1 << 4), /*!< Output binary tags as-is, dropping non-ASCII */ + OrthancPluginDicomToJsonFlags_ConvertBinaryToNull = (1 << 5), /*!< Signal binary tags as null values */ + + _OrthancPluginDicomToJsonFlags_INTERNAL = 0x7fffffff + } OrthancPluginDicomToJsonFlags; + + + /** + * Flags to the creation of a DICOM file. + * @ingroup Toolbox + * @see OrthancPluginCreateDicom() + **/ + typedef enum + { + OrthancPluginCreateDicomFlags_None = 0, + OrthancPluginCreateDicomFlags_DecodeDataUriScheme = (1 << 0), /*!< Decode fields encoded using data URI scheme */ + OrthancPluginCreateDicomFlags_GenerateIdentifiers = (1 << 1), /*!< Automatically generate DICOM identifiers */ + + _OrthancPluginCreateDicomFlags_INTERNAL = 0x7fffffff + } OrthancPluginCreateDicomFlags; + + + /** + * The constraints on the DICOM identifiers that must be supported + * by the database plugins. + * @deprecated Plugins using OrthancPluginConstraintType will be faster + **/ + typedef enum + { + OrthancPluginIdentifierConstraint_Equal = 1, /*!< Equal */ + OrthancPluginIdentifierConstraint_SmallerOrEqual = 2, /*!< Less or equal */ + OrthancPluginIdentifierConstraint_GreaterOrEqual = 3, /*!< More or equal */ + OrthancPluginIdentifierConstraint_Wildcard = 4, /*!< Case-sensitive wildcard matching (with * and ?) */ + + _OrthancPluginIdentifierConstraint_INTERNAL = 0x7fffffff + } OrthancPluginIdentifierConstraint; + + + /** + * The constraints on the tags (main DICOM tags and identifier tags) + * that must be supported by the database plugins. + **/ + typedef enum + { + OrthancPluginConstraintType_Equal = 1, /*!< Equal */ + OrthancPluginConstraintType_SmallerOrEqual = 2, /*!< Less or equal */ + OrthancPluginConstraintType_GreaterOrEqual = 3, /*!< More or equal */ + OrthancPluginConstraintType_Wildcard = 4, /*!< Wildcard matching */ + OrthancPluginConstraintType_List = 5, /*!< List of values */ + + _OrthancPluginConstraintType_INTERNAL = 0x7fffffff + } OrthancPluginConstraintType; + + + /** + * The origin of a DICOM instance that has been received by Orthanc. + **/ + typedef enum + { + OrthancPluginInstanceOrigin_Unknown = 1, /*!< Unknown origin */ + OrthancPluginInstanceOrigin_DicomProtocol = 2, /*!< Instance received through DICOM protocol */ + OrthancPluginInstanceOrigin_RestApi = 3, /*!< Instance received through REST API of Orthanc */ + OrthancPluginInstanceOrigin_Plugin = 4, /*!< Instance added to Orthanc by a plugin */ + OrthancPluginInstanceOrigin_Lua = 5, /*!< Instance added to Orthanc by a Lua script */ + + _OrthancPluginInstanceOrigin_INTERNAL = 0x7fffffff + } OrthancPluginInstanceOrigin; + + + /** + * The possible status for one single step of a job. + **/ + typedef enum + { + OrthancPluginJobStepStatus_Success = 1, /*!< The job has successfully executed all its steps */ + OrthancPluginJobStepStatus_Failure = 2, /*!< The job has failed while executing this step */ + OrthancPluginJobStepStatus_Continue = 3 /*!< The job has still data to process after this step */ + } OrthancPluginJobStepStatus; + + + /** + * Explains why the job should stop and release the resources it has + * allocated. This is especially important to disambiguate between + * the "paused" condition and the "final" conditions (success, + * failure, or canceled). + **/ + typedef enum + { + OrthancPluginJobStopReason_Success = 1, /*!< The job has succeeded */ + OrthancPluginJobStopReason_Paused = 2, /*!< The job was paused, and will be resumed later */ + OrthancPluginJobStopReason_Failure = 3, /*!< The job has failed, and might be resubmitted later */ + OrthancPluginJobStopReason_Canceled = 4 /*!< The job was canceled, and might be resubmitted later */ + } OrthancPluginJobStopReason; + + + /** + * The available types of metrics. + **/ + typedef enum + { + OrthancPluginMetricsType_Default, /*!< Default metrics */ + + /** + * This metrics represents a time duration. Orthanc will keep the + * maximum value of the metrics over a sliding window of ten + * seconds, which is useful if the metrics is sampled frequently. + **/ + OrthancPluginMetricsType_Timer + } OrthancPluginMetricsType; + + + /** + * The available modes to export a binary DICOM tag into a DICOMweb + * JSON or XML document. + **/ + typedef enum + { + OrthancPluginDicomWebBinaryMode_Ignore, /*!< Don't include binary tags */ + OrthancPluginDicomWebBinaryMode_InlineBinary, /*!< Inline encoding using Base64 */ + OrthancPluginDicomWebBinaryMode_BulkDataUri /*!< Use a bulk data URI field */ + } OrthancPluginDicomWebBinaryMode; + + + + /** + * @brief A memory buffer allocated by the core system of Orthanc. + * + * A memory buffer allocated by the core system of Orthanc. When the + * content of the buffer is not useful anymore, it must be free by a + * call to ::OrthancPluginFreeMemoryBuffer(). + **/ + typedef struct + { + /** + * @brief The content of the buffer. + **/ + void* data; + + /** + * @brief The number of bytes in the buffer. + **/ + uint32_t size; + } OrthancPluginMemoryBuffer; + + + + + /** + * @brief Opaque structure that represents the HTTP connection to the client application. + * @ingroup Callback + **/ + typedef struct _OrthancPluginRestOutput_t OrthancPluginRestOutput; + + + + /** + * @brief Opaque structure that represents a DICOM instance received by Orthanc. + **/ + typedef struct _OrthancPluginDicomInstance_t OrthancPluginDicomInstance; + + + + /** + * @brief Opaque structure that represents an image that is uncompressed in memory. + * @ingroup Images + **/ + typedef struct _OrthancPluginImage_t OrthancPluginImage; + + + + /** + * @brief Opaque structure that represents the storage area that is actually used by Orthanc. + * @ingroup Images + **/ + typedef struct _OrthancPluginStorageArea_t OrthancPluginStorageArea; + + + + /** + * @brief Opaque structure to an object that represents a C-Find query for worklists. + * @ingroup DicomCallbacks + **/ + typedef struct _OrthancPluginWorklistQuery_t OrthancPluginWorklistQuery; + + + + /** + * @brief Opaque structure to an object that represents the answers to a C-Find query for worklists. + * @ingroup DicomCallbacks + **/ + typedef struct _OrthancPluginWorklistAnswers_t OrthancPluginWorklistAnswers; + + + + /** + * @brief Opaque structure to an object that represents a C-Find query. + * @ingroup DicomCallbacks + **/ + typedef struct _OrthancPluginFindQuery_t OrthancPluginFindQuery; + + + + /** + * @brief Opaque structure to an object that represents the answers to a C-Find query for worklists. + * @ingroup DicomCallbacks + **/ + typedef struct _OrthancPluginFindAnswers_t OrthancPluginFindAnswers; + + + + /** + * @brief Opaque structure to an object that can be used to check whether a DICOM instance matches a C-Find query. + * @ingroup Toolbox + **/ + typedef struct _OrthancPluginFindAnswers_t OrthancPluginFindMatcher; + + + + /** + * @brief Opaque structure to the set of remote Orthanc Peers that are known to the local Orthanc server. + * @ingroup Toolbox + **/ + typedef struct _OrthancPluginPeers_t OrthancPluginPeers; + + + + /** + * @brief Opaque structure to a job to be executed by Orthanc. + * @ingroup Toolbox + **/ + typedef struct _OrthancPluginJob_t OrthancPluginJob; + + + + /** + * @brief Opaque structure that represents a node in a JSON or XML + * document used in DICOMweb. + * @ingroup Toolbox + **/ + typedef struct _OrthancPluginDicomWebNode_t OrthancPluginDicomWebNode; + + + + /** + * @brief Signature of a callback function that answers to a REST request. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginRestCallback) ( + OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request); + + + + /** + * @brief Signature of a callback function that is triggered when Orthanc receives a DICOM instance. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginOnStoredInstanceCallback) ( + OrthancPluginDicomInstance* instance, + const char* instanceId); + + + + /** + * @brief Signature of a callback function that is triggered when a change happens to some DICOM resource. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginOnChangeCallback) ( + OrthancPluginChangeType changeType, + OrthancPluginResourceType resourceType, + const char* resourceId); + + + + /** + * @brief Signature of a callback function to decode a DICOM instance as an image. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginDecodeImageCallback) ( + OrthancPluginImage** target, + const void* dicom, + const uint32_t size, + uint32_t frameIndex); + + + + /** + * @brief Signature of a function to free dynamic memory. + * @ingroup Callbacks + **/ + typedef void (*OrthancPluginFree) (void* buffer); + + + + /** + * @brief Signature of a function to set the content of a node + * encoding a binary DICOM tag, into a JSON or XML document + * generated for DICOMweb. + * @ingroup Callbacks + **/ + typedef void (*OrthancPluginDicomWebSetBinaryNode) ( + OrthancPluginDicomWebNode* node, + OrthancPluginDicomWebBinaryMode mode, + const char* bulkDataUri); + + + + /** + * @brief Callback for writing to the storage area. + * + * Signature of a callback function that is triggered when Orthanc writes a file to the storage area. + * + * @param uuid The UUID of the file. + * @param content The content of the file. + * @param size The size of the file. + * @param type The content type corresponding to this file. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginStorageCreate) ( + const char* uuid, + const void* content, + int64_t size, + OrthancPluginContentType type); + + + + /** + * @brief Callback for reading from the storage area. + * + * Signature of a callback function that is triggered when Orthanc reads a file from the storage area. + * + * @param content The content of the file (output). + * @param size The size of the file (output). + * @param uuid The UUID of the file of interest. + * @param type The content type corresponding to this file. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginStorageRead) ( + void** content, + int64_t* size, + const char* uuid, + OrthancPluginContentType type); + + + + /** + * @brief Callback for removing a file from the storage area. + * + * Signature of a callback function that is triggered when Orthanc deletes a file from the storage area. + * + * @param uuid The UUID of the file to be removed. + * @param type The content type corresponding to this file. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginStorageRemove) ( + const char* uuid, + OrthancPluginContentType type); + + + + /** + * @brief Callback to handle the C-Find SCP requests for worklists. + * + * Signature of a callback function that is triggered when Orthanc + * receives a C-Find SCP request against modality worklists. + * + * @param answers The target structure where answers must be stored. + * @param query The worklist query. + * @param issuerAet The Application Entity Title (AET) of the modality from which the request originates. + * @param calledAet The Application Entity Title (AET) of the modality that is called by the request. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginWorklistCallback) ( + OrthancPluginWorklistAnswers* answers, + const OrthancPluginWorklistQuery* query, + const char* issuerAet, + const char* calledAet); + + + + /** + * @brief Callback to filter incoming HTTP requests received by Orthanc. + * + * Signature of a callback function that is triggered whenever + * Orthanc receives an HTTP/REST request, and that answers whether + * this request should be allowed. If the callback returns "0" + * ("false"), the server answers with HTTP status code 403 + * (Forbidden). + * + * @param method The HTTP method used by the request. + * @param uri The URI of interest. + * @param ip The IP address of the HTTP client. + * @param headersCount The number of HTTP headers. + * @param headersKeys The keys of the HTTP headers (always converted to low-case). + * @param headersValues The values of the HTTP headers. + * @return 0 if forbidden access, 1 if allowed access, -1 if error. + * @ingroup Callback + * @deprecated Please instead use OrthancPluginIncomingHttpRequestFilter2() + **/ + typedef int32_t (*OrthancPluginIncomingHttpRequestFilter) ( + OrthancPluginHttpMethod method, + const char* uri, + const char* ip, + uint32_t headersCount, + const char* const* headersKeys, + const char* const* headersValues); + + + + /** + * @brief Callback to filter incoming HTTP requests received by Orthanc. + * + * Signature of a callback function that is triggered whenever + * Orthanc receives an HTTP/REST request, and that answers whether + * this request should be allowed. If the callback returns "0" + * ("false"), the server answers with HTTP status code 403 + * (Forbidden). + * + * @param method The HTTP method used by the request. + * @param uri The URI of interest. + * @param ip The IP address of the HTTP client. + * @param headersCount The number of HTTP headers. + * @param headersKeys The keys of the HTTP headers (always converted to low-case). + * @param headersValues The values of the HTTP headers. + * @param getArgumentsCount The number of GET arguments (only for the GET HTTP method). + * @param getArgumentsKeys The keys of the GET arguments (only for the GET HTTP method). + * @param getArgumentsValues The values of the GET arguments (only for the GET HTTP method). + * @return 0 if forbidden access, 1 if allowed access, -1 if error. + * @ingroup Callback + **/ + typedef int32_t (*OrthancPluginIncomingHttpRequestFilter2) ( + OrthancPluginHttpMethod method, + const char* uri, + const char* ip, + uint32_t headersCount, + const char* const* headersKeys, + const char* const* headersValues, + uint32_t getArgumentsCount, + const char* const* getArgumentsKeys, + const char* const* getArgumentsValues); + + + + /** + * @brief Callback to handle incoming C-Find SCP requests. + * + * Signature of a callback function that is triggered whenever + * Orthanc receives a C-Find SCP request not concerning modality + * worklists. + * + * @param answers The target structure where answers must be stored. + * @param query The worklist query. + * @param issuerAet The Application Entity Title (AET) of the modality from which the request originates. + * @param calledAet The Application Entity Title (AET) of the modality that is called by the request. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginFindCallback) ( + OrthancPluginFindAnswers* answers, + const OrthancPluginFindQuery* query, + const char* issuerAet, + const char* calledAet); + + + + /** + * @brief Callback to handle incoming C-Move SCP requests. + * + * Signature of a callback function that is triggered whenever + * Orthanc receives a C-Move SCP request. The callback receives the + * type of the resource of interest (study, series, instance...) + * together with the DICOM tags containing its identifiers. In turn, + * the plugin must create a driver object that will be responsible + * for driving the successive move suboperations. + * + * @param resourceType The type of the resource of interest. Note + * that this might be set to ResourceType_None if the + * QueryRetrieveLevel (0008,0052) tag was not provided by the + * issuer (i.e. the originator modality). + * @param patientId Content of the PatientID (0x0010, 0x0020) tag of the resource of interest. Might be NULL. + * @param accessionNumber Content of the AccessionNumber (0x0008, 0x0050) tag. Might be NULL. + * @param studyInstanceUid Content of the StudyInstanceUID (0x0020, 0x000d) tag. Might be NULL. + * @param seriesInstanceUid Content of the SeriesInstanceUID (0x0020, 0x000e) tag. Might be NULL. + * @param sopInstanceUid Content of the SOPInstanceUID (0x0008, 0x0018) tag. Might be NULL. + * @param originatorAet The Application Entity Title (AET) of the + * modality from which the request originates. + * @param sourceAet The Application Entity Title (AET) of the + * modality that should send its DICOM files to another modality. + * @param targetAet The Application Entity Title (AET) of the + * modality that should receive the DICOM files. + * @param originatorId The Message ID issued by the originator modality, + * as found in tag (0000,0110) of the DICOM query emitted by the issuer. + * + * @return The NULL value if the plugin cannot deal with this query, + * or a pointer to the driver object that is responsible for + * handling the successive move suboperations. + * + * @note If targetAet equals sourceAet, this is actually a query/retrieve operation. + * @ingroup DicomCallbacks + **/ + typedef void* (*OrthancPluginMoveCallback) ( + OrthancPluginResourceType resourceType, + const char* patientId, + const char* accessionNumber, + const char* studyInstanceUid, + const char* seriesInstanceUid, + const char* sopInstanceUid, + const char* originatorAet, + const char* sourceAet, + const char* targetAet, + uint16_t originatorId); + + + /** + * @brief Callback to read the size of a C-Move driver. + * + * Signature of a callback function that returns the number of + * C-Move suboperations that are to be achieved by the given C-Move + * driver. This driver is the return value of a previous call to the + * OrthancPluginMoveCallback() callback. + * + * @param moveDriver The C-Move driver of interest. + * @return The number of suboperations. + * @ingroup DicomCallbacks + **/ + typedef uint32_t (*OrthancPluginGetMoveSize) (void* moveDriver); + + + /** + * @brief Callback to apply one C-Move suboperation. + * + * Signature of a callback function that applies the next C-Move + * suboperation that os to be achieved by the given C-Move + * driver. This driver is the return value of a previous call to the + * OrthancPluginMoveCallback() callback. + * + * @param moveDriver The C-Move driver of interest. + * @return 0 if success, or the error code if failure. + * @ingroup DicomCallbacks + **/ + typedef OrthancPluginErrorCode (*OrthancPluginApplyMove) (void* moveDriver); + + + /** + * @brief Callback to free one C-Move driver. + * + * Signature of a callback function that releases the resources + * allocated by the given C-Move driver. This driver is the return + * value of a previous call to the OrthancPluginMoveCallback() + * callback. + * + * @param moveDriver The C-Move driver of interest. + * @ingroup DicomCallbacks + **/ + typedef void (*OrthancPluginFreeMove) (void* moveDriver); + + + /** + * @brief Callback to finalize one custom job. + * + * Signature of a callback function that releases all the resources + * allocated by the given job. This job is the argument provided to + * OrthancPluginCreateJob(). + * + * @param job The job of interest. + * @ingroup Toolbox + **/ + typedef void (*OrthancPluginJobFinalize) (void* job); + + + /** + * @brief Callback to check the progress of one custom job. + * + * Signature of a callback function that returns the progress of the + * job. + * + * @param job The job of interest. + * @return The progress, as a floating-point number ranging from 0 to 1. + * @ingroup Toolbox + **/ + typedef float (*OrthancPluginJobGetProgress) (void* job); + + + /** + * @brief Callback to retrieve the content of one custom job. + * + * Signature of a callback function that returns human-readable + * statistics about the job. This statistics must be formatted as a + * JSON object. This information is notably displayed in the "Jobs" + * tab of "Orthanc Explorer". + * + * @param job The job of interest. + * @return The statistics, as a JSON object encoded as a string. + * @ingroup Toolbox + **/ + typedef const char* (*OrthancPluginJobGetContent) (void* job); + + + /** + * @brief Callback to serialize one custom job. + * + * Signature of a callback function that returns a serialized + * version of the job, formatted as a JSON object. This + * serialization is stored in the Orthanc database, and is used to + * reload the job on the restart of Orthanc. The "unserialization" + * callback (with OrthancPluginJobsUnserializer signature) will + * receive this serialized object. + * + * @param job The job of interest. + * @return The serialized job, as a JSON object encoded as a string. + * @see OrthancPluginRegisterJobsUnserializer() + * @ingroup Toolbox + **/ + typedef const char* (*OrthancPluginJobGetSerialized) (void* job); + + + /** + * @brief Callback to execute one step of a custom job. + * + * Signature of a callback function that executes one step in the + * job. The jobs engine of Orthanc will make successive calls to + * this method, as long as it returns + * OrthancPluginJobStepStatus_Continue. + * + * @param job The job of interest. + * @return The status of execution. + * @ingroup Toolbox + **/ + typedef OrthancPluginJobStepStatus (*OrthancPluginJobStep) (void* job); + + + /** + * @brief Callback executed once one custom job leaves the "running" state. + * + * Signature of a callback function that is invoked once a job + * leaves the "running" state. This can happen if the previous call + * to OrthancPluginJobStep has failed/succeeded, if the host Orthanc + * server is being stopped, or if the user manually tags the job as + * paused/canceled. This callback allows the plugin to free + * resources allocated for running this custom job (e.g. to stop + * threads, or to remove temporary files). + * + * Note that handling pauses might involves a specific treatment + * (such a stopping threads, but keeping temporary files on the + * disk). This "paused" situation can be checked by looking at the + * "reason" parameter. + * + * @param job The job of interest. + * @param reason The reason for leaving the "running" state. + * @return 0 if success, or the error code if failure. + * @ingroup Toolbox + **/ + typedef OrthancPluginErrorCode (*OrthancPluginJobStop) (void* job, + OrthancPluginJobStopReason reason); + + + /** + * @brief Callback executed once one stopped custom job is started again. + * + * Signature of a callback function that is invoked once a job + * leaves the "failure/canceled" state, to be started again. This + * function will typically reset the progress to zero. Note that + * before being actually executed, the job would first be tagged as + * "pending" in the Orthanc jobs engine. + * + * @param job The job of interest. + * @return 0 if success, or the error code if failure. + * @ingroup Toolbox + **/ + typedef OrthancPluginErrorCode (*OrthancPluginJobReset) (void* job); + + + /** + * @brief Callback executed to unserialize a custom job. + * + * Signature of a callback function that unserializes a job that was + * saved in the Orthanc database. + * + * @param jobType The type of the job, as provided to OrthancPluginCreateJob(). + * @param serialized The serialization of the job, as provided by OrthancPluginJobGetSerialized. + * @return The unserialized job (as created by OrthancPluginCreateJob()), or NULL + * if this unserializer cannot handle this job type. + * @see OrthancPluginRegisterJobsUnserializer() + * @ingroup Callbacks + **/ + typedef OrthancPluginJob* (*OrthancPluginJobsUnserializer) (const char* jobType, + const char* serialized); + + + + /** + * @brief Callback executed to update the metrics of the plugin. + * + * Signature of a callback function that is called by Orthanc + * whenever a monitoring tool (such as Prometheus) asks the current + * values of the metrics. This callback gives the plugin a chance to + * update its metrics, by calling OrthancPluginSetMetricsValue(). + * This is typically useful for metrics that are expensive to + * acquire. + * + * @see OrthancPluginRegisterRefreshMetrics() + * @ingroup Callbacks + **/ + typedef void (*OrthancPluginRefreshMetricsCallback) (); + + + + /** + * @brief Callback executed to encode a binary tag in DICOMweb. + * + * Signature of a callback function that is called by Orthanc + * whenever a DICOM tag that contains a binary value must be written + * to a JSON or XML node, while a DICOMweb document is being + * generated. The value representation (VR) of the DICOM tag can be + * OB, OD, OF, OL, OW, or UN. + * + * @see OrthancPluginEncodeDicomWebJson() and OrthancPluginEncodeDicomWebXml() + * @param node The node being generated, as provided by Orthanc. + * @param setter The setter to be used to encode the content of the node. If + * the setter is not called, the binary tag is not written to the output document. + * @param levelDepth The depth of the node in the DICOM hierarchy of sequences. + * This parameter gives the number of elements in the "levelTagGroup", + * "levelTagElement", and "levelIndex" arrays. + * @param levelTagGroup The group of the parent DICOM tags in the hierarchy. + * @param levelTagElement The element of the parent DICOM tags in the hierarchy. + * @param levelIndex The index of the node in the parent sequences of the hiearchy. + * @param tagGroup The group of the DICOM tag of interest. + * @param tagElement The element of the DICOM tag of interest. + * @param vr The value representation of the binary DICOM node. + * @ingroup Callbacks + **/ + typedef void (*OrthancPluginDicomWebBinaryCallback) ( + OrthancPluginDicomWebNode* node, + OrthancPluginDicomWebSetBinaryNode setter, + uint32_t levelDepth, + const uint16_t* levelTagGroup, + const uint16_t* levelTagElement, + const uint32_t* levelIndex, + uint16_t tagGroup, + uint16_t tagElement, + OrthancPluginValueRepresentation vr); + + + + /** + * @brief Data structure that contains information about the Orthanc core. + **/ + typedef struct _OrthancPluginContext_t + { + void* pluginsManager; + const char* orthancVersion; + OrthancPluginFree Free; + OrthancPluginErrorCode (*InvokeService) (struct _OrthancPluginContext_t* context, + _OrthancPluginService service, + const void* params); + } OrthancPluginContext; + + + + /** + * @brief An entry in the dictionary of DICOM tags. + **/ + typedef struct + { + uint16_t group; /*!< The group of the tag */ + uint16_t element; /*!< The element of the tag */ + OrthancPluginValueRepresentation vr; /*!< The value representation of the tag */ + uint32_t minMultiplicity; /*!< The minimum multiplicity of the tag */ + uint32_t maxMultiplicity; /*!< The maximum multiplicity of the tag (0 means arbitrary) */ + } OrthancPluginDictionaryEntry; + + + + /** + * @brief Free a string. + * + * Free a string that was allocated by the core system of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param str The string to be freed. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginFreeString( + OrthancPluginContext* context, + char* str) + { + if (str != NULL) + { + context->Free(str); + } + } + + + /** + * @brief Check that the version of the hosting Orthanc is above a given version. + * + * This function checks whether the version of the Orthanc server + * running this plugin, is above the given version. Contrarily to + * OrthancPluginCheckVersion(), it is up to the developer of the + * plugin to make sure that all the Orthanc SDK services called by + * the plugin are actually implemented in the given version of + * Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param expectedMajor Expected major version. + * @param expectedMinor Expected minor version. + * @param expectedRevision Expected revision. + * @return 1 if and only if the versions are compatible. If the + * result is 0, the initialization of the plugin should fail. + * @see OrthancPluginCheckVersion + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE int OrthancPluginCheckVersionAdvanced( + OrthancPluginContext* context, + int expectedMajor, + int expectedMinor, + int expectedRevision) + { + int major, minor, revision; + + if (sizeof(int32_t) != sizeof(OrthancPluginErrorCode) || + sizeof(int32_t) != sizeof(OrthancPluginHttpMethod) || + sizeof(int32_t) != sizeof(_OrthancPluginService) || + sizeof(int32_t) != sizeof(_OrthancPluginProperty) || + sizeof(int32_t) != sizeof(OrthancPluginPixelFormat) || + sizeof(int32_t) != sizeof(OrthancPluginContentType) || + sizeof(int32_t) != sizeof(OrthancPluginResourceType) || + sizeof(int32_t) != sizeof(OrthancPluginChangeType) || + sizeof(int32_t) != sizeof(OrthancPluginCompressionType) || + sizeof(int32_t) != sizeof(OrthancPluginImageFormat) || + sizeof(int32_t) != sizeof(OrthancPluginValueRepresentation) || + sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFormat) || + sizeof(int32_t) != sizeof(OrthancPluginDicomToJsonFlags) || + sizeof(int32_t) != sizeof(OrthancPluginCreateDicomFlags) || + sizeof(int32_t) != sizeof(OrthancPluginIdentifierConstraint) || + sizeof(int32_t) != sizeof(OrthancPluginInstanceOrigin) || + sizeof(int32_t) != sizeof(OrthancPluginJobStepStatus) || + sizeof(int32_t) != sizeof(OrthancPluginConstraintType) || + sizeof(int32_t) != sizeof(OrthancPluginMetricsType) || + sizeof(int32_t) != sizeof(OrthancPluginDicomWebBinaryMode)) + { + /* Mismatch in the size of the enumerations */ + return 0; + } + + /* Assume compatibility with the mainline */ + if (!strcmp(context->orthancVersion, "mainline")) + { + return 1; + } + + /* Parse the version of the Orthanc core */ + if ( +#ifdef _MSC_VER + sscanf_s +#else + sscanf +#endif + (context->orthancVersion, "%4d.%4d.%4d", &major, &minor, &revision) != 3) + { + return 0; + } + + /* Check the major number of the version */ + + if (major > expectedMajor) + { + return 1; + } + + if (major < expectedMajor) + { + return 0; + } + + /* Check the minor number of the version */ + + if (minor > expectedMinor) + { + return 1; + } + + if (minor < expectedMinor) + { + return 0; + } + + /* Check the revision number of the version */ + + if (revision >= expectedRevision) + { + return 1; + } + else + { + return 0; + } + } + + + /** + * @brief Check the compatibility of the plugin wrt. the version of its hosting Orthanc. + * + * This function checks whether the version of the Orthanc server + * running this plugin, is above the version of the current Orthanc + * SDK header. This guarantees that the plugin is compatible with + * the hosting Orthanc (i.e. it will not call unavailable services). + * The result of this function should always be checked in the + * OrthancPluginInitialize() entry point of the plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return 1 if and only if the versions are compatible. If the + * result is 0, the initialization of the plugin should fail. + * @see OrthancPluginCheckVersionAdvanced + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE int OrthancPluginCheckVersion( + OrthancPluginContext* context) + { + return OrthancPluginCheckVersionAdvanced( + context, + ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, + ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); + } + + + /** + * @brief Free a memory buffer. + * + * Free a memory buffer that was allocated by the core system of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param buffer The memory buffer to release. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginFreeMemoryBuffer( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* buffer) + { + context->Free(buffer->data); + } + + + /** + * @brief Log an error. + * + * Log an error message using the Orthanc logging system. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param message The message to be logged. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginLogError( + OrthancPluginContext* context, + const char* message) + { + context->InvokeService(context, _OrthancPluginService_LogError, message); + } + + + /** + * @brief Log a warning. + * + * Log a warning message using the Orthanc logging system. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param message The message to be logged. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginLogWarning( + OrthancPluginContext* context, + const char* message) + { + context->InvokeService(context, _OrthancPluginService_LogWarning, message); + } + + + /** + * @brief Log an information. + * + * Log an information message using the Orthanc logging system. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param message The message to be logged. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginLogInfo( + OrthancPluginContext* context, + const char* message) + { + context->InvokeService(context, _OrthancPluginService_LogInfo, message); + } + + + + typedef struct + { + const char* pathRegularExpression; + OrthancPluginRestCallback callback; + } _OrthancPluginRestCallback; + + /** + * @brief Register a REST callback. + * + * This function registers a REST callback against a regular + * expression for a URI. This function must be called during the + * initialization of the plugin, i.e. inside the + * OrthancPluginInitialize() public function. + * + * Each REST callback is guaranteed to run in mutual exclusion. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param pathRegularExpression Regular expression for the URI. May contain groups. + * @param callback The callback function to handle the REST call. + * @see OrthancPluginRegisterRestCallbackNoLock() + * + * @note + * The regular expression is case sensitive and must follow the + * [Perl syntax](https://www.boost.org/doc/libs/1_67_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html). + * + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterRestCallback( + OrthancPluginContext* context, + const char* pathRegularExpression, + OrthancPluginRestCallback callback) + { + _OrthancPluginRestCallback params; + params.pathRegularExpression = pathRegularExpression; + params.callback = callback; + context->InvokeService(context, _OrthancPluginService_RegisterRestCallback, ¶ms); + } + + + + /** + * @brief Register a REST callback, without locking. + * + * This function registers a REST callback against a regular + * expression for a URI. This function must be called during the + * initialization of the plugin, i.e. inside the + * OrthancPluginInitialize() public function. + * + * Contrarily to OrthancPluginRegisterRestCallback(), the callback + * will NOT be invoked in mutual exclusion. This can be useful for + * high-performance plugins that must handle concurrent requests + * (Orthanc uses a pool of threads, one thread being assigned to + * each incoming HTTP request). Of course, if using this function, + * it is up to the plugin to implement the required locking + * mechanisms. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param pathRegularExpression Regular expression for the URI. May contain groups. + * @param callback The callback function to handle the REST call. + * @see OrthancPluginRegisterRestCallback() + * + * @note + * The regular expression is case sensitive and must follow the + * [Perl syntax](https://www.boost.org/doc/libs/1_67_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html). + * + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterRestCallbackNoLock( + OrthancPluginContext* context, + const char* pathRegularExpression, + OrthancPluginRestCallback callback) + { + _OrthancPluginRestCallback params; + params.pathRegularExpression = pathRegularExpression; + params.callback = callback; + context->InvokeService(context, _OrthancPluginService_RegisterRestCallbackNoLock, ¶ms); + } + + + + typedef struct + { + OrthancPluginOnStoredInstanceCallback callback; + } _OrthancPluginOnStoredInstanceCallback; + + /** + * @brief Register a callback for received instances. + * + * This function registers a callback function that is called + * whenever a new DICOM instance is stored into the Orthanc core. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback function. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterOnStoredInstanceCallback( + OrthancPluginContext* context, + OrthancPluginOnStoredInstanceCallback callback) + { + _OrthancPluginOnStoredInstanceCallback params; + params.callback = callback; + + context->InvokeService(context, _OrthancPluginService_RegisterOnStoredInstanceCallback, ¶ms); + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + const char* answer; + uint32_t answerSize; + const char* mimeType; + } _OrthancPluginAnswerBuffer; + + /** + * @brief Answer to a REST request. + * + * This function answers to a REST request with the content of a memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param answer Pointer to the memory buffer containing the answer. + * @param answerSize Number of bytes of the answer. + * @param mimeType The MIME type of the answer. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginAnswerBuffer( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* answer, + uint32_t answerSize, + const char* mimeType) + { + _OrthancPluginAnswerBuffer params; + params.output = output; + params.answer = answer; + params.answerSize = answerSize; + params.mimeType = mimeType; + context->InvokeService(context, _OrthancPluginService_AnswerBuffer, ¶ms); + } + + + typedef struct + { + OrthancPluginRestOutput* output; + OrthancPluginPixelFormat format; + uint32_t width; + uint32_t height; + uint32_t pitch; + const void* buffer; + } _OrthancPluginCompressAndAnswerPngImage; + + typedef struct + { + OrthancPluginRestOutput* output; + OrthancPluginImageFormat imageFormat; + OrthancPluginPixelFormat pixelFormat; + uint32_t width; + uint32_t height; + uint32_t pitch; + const void* buffer; + uint8_t quality; + } _OrthancPluginCompressAndAnswerImage; + + + /** + * @brief Answer to a REST request with a PNG image. + * + * This function answers to a REST request with a PNG image. The + * parameters of this function describe a memory buffer that + * contains an uncompressed image. The image will be automatically compressed + * as a PNG image by the core system of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param format The memory layout of the uncompressed image. + * @param width The width of the image. + * @param height The height of the image. + * @param pitch The pitch of the image (i.e. the number of bytes + * between 2 successive lines of the image in the memory buffer). + * @param buffer The memory buffer containing the uncompressed image. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginCompressAndAnswerPngImage( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + const void* buffer) + { + _OrthancPluginCompressAndAnswerImage params; + params.output = output; + params.imageFormat = OrthancPluginImageFormat_Png; + params.pixelFormat = format; + params.width = width; + params.height = height; + params.pitch = pitch; + params.buffer = buffer; + params.quality = 0; /* No quality for PNG */ + context->InvokeService(context, _OrthancPluginService_CompressAndAnswerImage, ¶ms); + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const char* instanceId; + } _OrthancPluginGetDicomForInstance; + + /** + * @brief Retrieve a DICOM instance using its Orthanc identifier. + * + * Retrieve a DICOM instance using its Orthanc identifier. The DICOM + * file is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param instanceId The Orthanc identifier of the DICOM instance of interest. + * @return 0 if success, or the error code if failure. + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetDicomForInstance( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* instanceId) + { + _OrthancPluginGetDicomForInstance params; + params.target = target; + params.instanceId = instanceId; + return context->InvokeService(context, _OrthancPluginService_GetDicomForInstance, ¶ms); + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const char* uri; + } _OrthancPluginRestApiGet; + + /** + * @brief Make a GET call to the built-in Orthanc REST API. + * + * Make a GET call to the built-in Orthanc REST API. The result to + * the query is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiGetAfterPlugins + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiGet( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri) + { + _OrthancPluginRestApiGet params; + params.target = target; + params.uri = uri; + return context->InvokeService(context, _OrthancPluginService_RestApiGet, ¶ms); + } + + + + /** + * @brief Make a GET call to the REST API, as tainted by the plugins. + * + * Make a GET call to the Orthanc REST API, after all the plugins + * are applied. In other words, if some plugin overrides or adds the + * called URI to the built-in Orthanc REST API, this call will + * return the result provided by this plugin. The result to the + * query is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiGet + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiGetAfterPlugins( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri) + { + _OrthancPluginRestApiGet params; + params.target = target; + params.uri = uri; + return context->InvokeService(context, _OrthancPluginService_RestApiGetAfterPlugins, ¶ms); + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const char* uri; + const char* body; + uint32_t bodySize; + } _OrthancPluginRestApiPostPut; + + /** + * @brief Make a POST call to the built-in Orthanc REST API. + * + * Make a POST call to the built-in Orthanc REST API. The result to + * the query is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @param body The body of the POST request. + * @param bodySize The size of the body. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiPostAfterPlugins + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiPost( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri, + const char* body, + uint32_t bodySize) + { + _OrthancPluginRestApiPostPut params; + params.target = target; + params.uri = uri; + params.body = body; + params.bodySize = bodySize; + return context->InvokeService(context, _OrthancPluginService_RestApiPost, ¶ms); + } + + + /** + * @brief Make a POST call to the REST API, as tainted by the plugins. + * + * Make a POST call to the Orthanc REST API, after all the plugins + * are applied. In other words, if some plugin overrides or adds the + * called URI to the built-in Orthanc REST API, this call will + * return the result provided by this plugin. The result to the + * query is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @param body The body of the POST request. + * @param bodySize The size of the body. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiPost + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiPostAfterPlugins( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri, + const char* body, + uint32_t bodySize) + { + _OrthancPluginRestApiPostPut params; + params.target = target; + params.uri = uri; + params.body = body; + params.bodySize = bodySize; + return context->InvokeService(context, _OrthancPluginService_RestApiPostAfterPlugins, ¶ms); + } + + + + /** + * @brief Make a DELETE call to the built-in Orthanc REST API. + * + * Make a DELETE call to the built-in Orthanc REST API. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param uri The URI to delete in the built-in Orthanc API. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiDeleteAfterPlugins + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiDelete( + OrthancPluginContext* context, + const char* uri) + { + return context->InvokeService(context, _OrthancPluginService_RestApiDelete, uri); + } + + + /** + * @brief Make a DELETE call to the REST API, as tainted by the plugins. + * + * Make a DELETE call to the Orthanc REST API, after all the plugins + * are applied. In other words, if some plugin overrides or adds the + * called URI to the built-in Orthanc REST API, this call will + * return the result provided by this plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param uri The URI to delete in the built-in Orthanc API. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiDelete + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiDeleteAfterPlugins( + OrthancPluginContext* context, + const char* uri) + { + return context->InvokeService(context, _OrthancPluginService_RestApiDeleteAfterPlugins, uri); + } + + + + /** + * @brief Make a PUT call to the built-in Orthanc REST API. + * + * Make a PUT call to the built-in Orthanc REST API. The result to + * the query is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @param body The body of the PUT request. + * @param bodySize The size of the body. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiPutAfterPlugins + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiPut( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri, + const char* body, + uint32_t bodySize) + { + _OrthancPluginRestApiPostPut params; + params.target = target; + params.uri = uri; + params.body = body; + params.bodySize = bodySize; + return context->InvokeService(context, _OrthancPluginService_RestApiPut, ¶ms); + } + + + + /** + * @brief Make a PUT call to the REST API, as tainted by the plugins. + * + * Make a PUT call to the Orthanc REST API, after all the plugins + * are applied. In other words, if some plugin overrides or adds the + * called URI to the built-in Orthanc REST API, this call will + * return the result provided by this plugin. The result to the + * query is stored into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @param body The body of the PUT request. + * @param bodySize The size of the body. + * @return 0 if success, or the error code if failure. + * @note If the resource is not existing (error 404), the error code will be OrthancPluginErrorCode_UnknownResource. + * @see OrthancPluginRestApiPut + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiPutAfterPlugins( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri, + const char* body, + uint32_t bodySize) + { + _OrthancPluginRestApiPostPut params; + params.target = target; + params.uri = uri; + params.body = body; + params.bodySize = bodySize; + return context->InvokeService(context, _OrthancPluginService_RestApiPutAfterPlugins, ¶ms); + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + const char* argument; + } _OrthancPluginOutputPlusArgument; + + /** + * @brief Redirect a REST request. + * + * This function answers to a REST request by redirecting the user + * to another URI using HTTP status 301. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param redirection Where to redirect. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRedirect( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* redirection) + { + _OrthancPluginOutputPlusArgument params; + params.output = output; + params.argument = redirection; + context->InvokeService(context, _OrthancPluginService_Redirect, ¶ms); + } + + + + typedef struct + { + char** result; + const char* argument; + } _OrthancPluginRetrieveDynamicString; + + /** + * @brief Look for a patient. + * + * Look for a patient stored in Orthanc, using its Patient ID tag (0x0010, 0x0020). + * This function uses the database index to run as fast as possible (it does not loop + * over all the stored patients). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param patientID The Patient ID of interest. + * @return The NULL value if the patient is non-existent, or a string containing the + * Orthanc ID of the patient. This string must be freed by OrthancPluginFreeString(). + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginLookupPatient( + OrthancPluginContext* context, + const char* patientID) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = patientID; + + if (context->InvokeService(context, _OrthancPluginService_LookupPatient, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Look for a study. + * + * Look for a study stored in Orthanc, using its Study Instance UID tag (0x0020, 0x000d). + * This function uses the database index to run as fast as possible (it does not loop + * over all the stored studies). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param studyUID The Study Instance UID of interest. + * @return The NULL value if the study is non-existent, or a string containing the + * Orthanc ID of the study. This string must be freed by OrthancPluginFreeString(). + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginLookupStudy( + OrthancPluginContext* context, + const char* studyUID) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = studyUID; + + if (context->InvokeService(context, _OrthancPluginService_LookupStudy, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Look for a study, using the accession number. + * + * Look for a study stored in Orthanc, using its Accession Number tag (0x0008, 0x0050). + * This function uses the database index to run as fast as possible (it does not loop + * over all the stored studies). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param accessionNumber The Accession Number of interest. + * @return The NULL value if the study is non-existent, or a string containing the + * Orthanc ID of the study. This string must be freed by OrthancPluginFreeString(). + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginLookupStudyWithAccessionNumber( + OrthancPluginContext* context, + const char* accessionNumber) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = accessionNumber; + + if (context->InvokeService(context, _OrthancPluginService_LookupStudyWithAccessionNumber, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Look for a series. + * + * Look for a series stored in Orthanc, using its Series Instance UID tag (0x0020, 0x000e). + * This function uses the database index to run as fast as possible (it does not loop + * over all the stored series). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param seriesUID The Series Instance UID of interest. + * @return The NULL value if the series is non-existent, or a string containing the + * Orthanc ID of the series. This string must be freed by OrthancPluginFreeString(). + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginLookupSeries( + OrthancPluginContext* context, + const char* seriesUID) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = seriesUID; + + if (context->InvokeService(context, _OrthancPluginService_LookupSeries, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Look for an instance. + * + * Look for an instance stored in Orthanc, using its SOP Instance UID tag (0x0008, 0x0018). + * This function uses the database index to run as fast as possible (it does not loop + * over all the stored instances). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param sopInstanceUID The SOP Instance UID of interest. + * @return The NULL value if the instance is non-existent, or a string containing the + * Orthanc ID of the instance. This string must be freed by OrthancPluginFreeString(). + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginLookupInstance( + OrthancPluginContext* context, + const char* sopInstanceUID) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = sopInstanceUID; + + if (context->InvokeService(context, _OrthancPluginService_LookupInstance, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + uint16_t status; + } _OrthancPluginSendHttpStatusCode; + + /** + * @brief Send a HTTP status code. + * + * This function answers to a REST request by sending a HTTP status + * code (such as "400 - Bad Request"). Note that: + * - Successful requests (status 200) must use ::OrthancPluginAnswerBuffer(). + * - Redirections (status 301) must use ::OrthancPluginRedirect(). + * - Unauthorized access (status 401) must use ::OrthancPluginSendUnauthorized(). + * - Methods not allowed (status 405) must use ::OrthancPluginSendMethodNotAllowed(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param status The HTTP status code to be sent. + * @ingroup REST + * @see OrthancPluginSendHttpStatus() + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSendHttpStatusCode( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + uint16_t status) + { + _OrthancPluginSendHttpStatusCode params; + params.output = output; + params.status = status; + context->InvokeService(context, _OrthancPluginService_SendHttpStatusCode, ¶ms); + } + + + /** + * @brief Signal that a REST request is not authorized. + * + * This function answers to a REST request by signaling that it is + * not authorized. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param realm The realm for the authorization process. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSendUnauthorized( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* realm) + { + _OrthancPluginOutputPlusArgument params; + params.output = output; + params.argument = realm; + context->InvokeService(context, _OrthancPluginService_SendUnauthorized, ¶ms); + } + + + /** + * @brief Signal that this URI does not support this HTTP method. + * + * This function answers to a REST request by signaling that the + * queried URI does not support this method. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param allowedMethods The allowed methods for this URI (e.g. "GET,POST" after a PUT or a POST request). + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSendMethodNotAllowed( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* allowedMethods) + { + _OrthancPluginOutputPlusArgument params; + params.output = output; + params.argument = allowedMethods; + context->InvokeService(context, _OrthancPluginService_SendMethodNotAllowed, ¶ms); + } + + + typedef struct + { + OrthancPluginRestOutput* output; + const char* key; + const char* value; + } _OrthancPluginSetHttpHeader; + + /** + * @brief Set a cookie. + * + * This function sets a cookie in the HTTP client. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param cookie The cookie to be set. + * @param value The value of the cookie. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSetCookie( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* cookie, + const char* value) + { + _OrthancPluginSetHttpHeader params; + params.output = output; + params.key = cookie; + params.value = value; + context->InvokeService(context, _OrthancPluginService_SetCookie, ¶ms); + } + + + /** + * @brief Set some HTTP header. + * + * This function sets a HTTP header in the HTTP answer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param key The HTTP header to be set. + * @param value The value of the HTTP header. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSetHttpHeader( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* key, + const char* value) + { + _OrthancPluginSetHttpHeader params; + params.output = output; + params.key = key; + params.value = value; + context->InvokeService(context, _OrthancPluginService_SetHttpHeader, ¶ms); + } + + + typedef struct + { + char** resultStringToFree; + const char** resultString; + int64_t* resultInt64; + const char* key; + OrthancPluginDicomInstance* instance; + OrthancPluginInstanceOrigin* resultOrigin; /* New in Orthanc 0.9.5 SDK */ + } _OrthancPluginAccessDicomInstance; + + + /** + * @brief Get the AET of a DICOM instance. + * + * This function returns the Application Entity Title (AET) of the + * DICOM modality from which a DICOM instance originates. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The AET if success, NULL if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceRemoteAet( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + const char* result; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultString = &result; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceRemoteAet, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Get the size of a DICOM file. + * + * This function returns the number of bytes of the given DICOM instance. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The size of the file, -1 in case of error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE int64_t OrthancPluginGetInstanceSize( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + int64_t size; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultInt64 = &size; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceSize, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return -1; + } + else + { + return size; + } + } + + + /** + * @brief Get the data of a DICOM file. + * + * This function returns a pointer to the content of the given DICOM instance. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The pointer to the DICOM data, NULL in case of error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceData( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + const char* result; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultString = &result; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceData, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Get the DICOM tag hierarchy as a JSON file. + * + * This function returns a pointer to a newly created string + * containing a JSON file. This JSON file encodes the tag hierarchy + * of the given DICOM instance. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The NULL value in case of error, or a string containing the JSON file. + * This string must be freed by OrthancPluginFreeString(). + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceJson( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + char* result; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultStringToFree = &result; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceJson, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Get the DICOM tag hierarchy as a JSON file (with simplification). + * + * This function returns a pointer to a newly created string + * containing a JSON file. This JSON file encodes the tag hierarchy + * of the given DICOM instance. In contrast with + * ::OrthancPluginGetInstanceJson(), the returned JSON file is in + * its simplified version. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The NULL value in case of error, or a string containing the JSON file. + * This string must be freed by OrthancPluginFreeString(). + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGetInstanceSimplifiedJson( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + char* result; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultStringToFree = &result; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceSimplifiedJson, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Check whether a DICOM instance is associated with some metadata. + * + * This function checks whether the DICOM instance of interest is + * associated with some metadata. As of Orthanc 0.8.1, in the + * callbacks registered by + * ::OrthancPluginRegisterOnStoredInstanceCallback(), the only + * possibly available metadata are "ReceptionDate", "RemoteAET" and + * "IndexInSeries". + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @param metadata The metadata of interest. + * @return 1 if the metadata is present, 0 if it is absent, -1 in case of error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE int OrthancPluginHasInstanceMetadata( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance, + const char* metadata) + { + int64_t result; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultInt64 = &result; + params.instance = instance; + params.key = metadata; + + if (context->InvokeService(context, _OrthancPluginService_HasInstanceMetadata, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return -1; + } + else + { + return (result != 0); + } + } + + + /** + * @brief Get the value of some metadata associated with a given DICOM instance. + * + * This functions returns the value of some metadata that is associated with the DICOM instance of interest. + * Before calling this function, the existence of the metadata must have been checked with + * ::OrthancPluginHasInstanceMetadata(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @param metadata The metadata of interest. + * @return The metadata value if success, NULL if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetInstanceMetadata( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance, + const char* metadata) + { + const char* result; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultString = &result; + params.instance = instance; + params.key = metadata; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceMetadata, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginStorageCreate create; + OrthancPluginStorageRead read; + OrthancPluginStorageRemove remove; + OrthancPluginFree free; + } _OrthancPluginRegisterStorageArea; + + /** + * @brief Register a custom storage area. + * + * This function registers a custom storage area, to replace the + * built-in way Orthanc stores its files on the filesystem. This + * function must be called during the initialization of the plugin, + * i.e. inside the OrthancPluginInitialize() public function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param create The callback function to store a file on the custom storage area. + * @param read The callback function to read a file from the custom storage area. + * @param remove The callback function to remove a file from the custom storage area. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterStorageArea( + OrthancPluginContext* context, + OrthancPluginStorageCreate create, + OrthancPluginStorageRead read, + OrthancPluginStorageRemove remove) + { + _OrthancPluginRegisterStorageArea params; + params.create = create; + params.read = read; + params.remove = remove; + +#ifdef __cplusplus + params.free = ::free; +#else + params.free = free; +#endif + + context->InvokeService(context, _OrthancPluginService_RegisterStorageArea, ¶ms); + } + + + + /** + * @brief Return the path to the Orthanc executable. + * + * This function returns the path to the Orthanc executable. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return NULL in the case of an error, or a newly allocated string + * containing the path. This string must be freed by + * OrthancPluginFreeString(). + **/ + ORTHANC_PLUGIN_INLINE char *OrthancPluginGetOrthancPath(OrthancPluginContext* context) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetOrthancPath, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Return the directory containing the Orthanc. + * + * This function returns the path to the directory containing the Orthanc executable. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return NULL in the case of an error, or a newly allocated string + * containing the path. This string must be freed by + * OrthancPluginFreeString(). + **/ + ORTHANC_PLUGIN_INLINE char *OrthancPluginGetOrthancDirectory(OrthancPluginContext* context) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetOrthancDirectory, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Return the path to the configuration file(s). + * + * This function returns the path to the configuration file(s) that + * was specified when starting Orthanc. Since version 0.9.1, this + * path can refer to a folder that stores a set of configuration + * files. This function is deprecated in favor of + * OrthancPluginGetConfiguration(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return NULL in the case of an error, or a newly allocated string + * containing the path. This string must be freed by + * OrthancPluginFreeString(). + * @see OrthancPluginGetConfiguration() + **/ + ORTHANC_PLUGIN_INLINE char *OrthancPluginGetConfigurationPath(OrthancPluginContext* context) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetConfigurationPath, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginOnChangeCallback callback; + } _OrthancPluginOnChangeCallback; + + /** + * @brief Register a callback to monitor changes. + * + * This function registers a callback function that is called + * whenever a change happens to some DICOM resource. + * + * @warning If your change callback has to call the REST API of + * Orthanc, you should make these calls in a separate thread (with + * the events passing through a message queue). Otherwise, this + * could result in deadlocks in the presence of other plugins or Lua + * scripts. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback function. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterOnChangeCallback( + OrthancPluginContext* context, + OrthancPluginOnChangeCallback callback) + { + _OrthancPluginOnChangeCallback params; + params.callback = callback; + + context->InvokeService(context, _OrthancPluginService_RegisterOnChangeCallback, ¶ms); + } + + + + typedef struct + { + const char* plugin; + _OrthancPluginProperty property; + const char* value; + } _OrthancPluginSetPluginProperty; + + + /** + * @brief Set the URI where the plugin provides its Web interface. + * + * For plugins that come with a Web interface, this function + * declares the entry path where to find this interface. This + * information is notably used in the "Plugins" page of Orthanc + * Explorer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param uri The root URI for this plugin. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSetRootUri( + OrthancPluginContext* context, + const char* uri) + { + _OrthancPluginSetPluginProperty params; + params.plugin = OrthancPluginGetName(); + params.property = _OrthancPluginProperty_RootUri; + params.value = uri; + + context->InvokeService(context, _OrthancPluginService_SetPluginProperty, ¶ms); + } + + + /** + * @brief Set a description for this plugin. + * + * Set a description for this plugin. It is displayed in the + * "Plugins" page of Orthanc Explorer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param description The description. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSetDescription( + OrthancPluginContext* context, + const char* description) + { + _OrthancPluginSetPluginProperty params; + params.plugin = OrthancPluginGetName(); + params.property = _OrthancPluginProperty_Description; + params.value = description; + + context->InvokeService(context, _OrthancPluginService_SetPluginProperty, ¶ms); + } + + + /** + * @brief Extend the JavaScript code of Orthanc Explorer. + * + * Add JavaScript code to customize the default behavior of Orthanc + * Explorer. This can for instance be used to add new buttons. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param javascript The custom JavaScript code. + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginExtendOrthancExplorer( + OrthancPluginContext* context, + const char* javascript) + { + _OrthancPluginSetPluginProperty params; + params.plugin = OrthancPluginGetName(); + params.property = _OrthancPluginProperty_OrthancExplorer; + params.value = javascript; + + context->InvokeService(context, _OrthancPluginService_SetPluginProperty, ¶ms); + } + + + typedef struct + { + char** result; + int32_t property; + const char* value; + } _OrthancPluginGlobalProperty; + + + /** + * @brief Get the value of a global property. + * + * Get the value of a global property that is stored in the Orthanc database. Global + * properties whose index is below 1024 are reserved by Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param property The global property of interest. + * @param defaultValue The value to return, if the global property is unset. + * @return The value of the global property, or NULL in the case of an error. This + * string must be freed by OrthancPluginFreeString(). + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGetGlobalProperty( + OrthancPluginContext* context, + int32_t property, + const char* defaultValue) + { + char* result; + + _OrthancPluginGlobalProperty params; + params.result = &result; + params.property = property; + params.value = defaultValue; + + if (context->InvokeService(context, _OrthancPluginService_GetGlobalProperty, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Set the value of a global property. + * + * Set the value of a global property into the Orthanc + * database. Setting a global property can be used by plugins to + * save their internal parameters. Plugins are only allowed to set + * properties whose index are above or equal to 1024 (properties + * below 1024 are read-only and reserved by Orthanc). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param property The global property of interest. + * @param value The value to be set in the global property. + * @return 0 if success, or the error code if failure. + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSetGlobalProperty( + OrthancPluginContext* context, + int32_t property, + const char* value) + { + _OrthancPluginGlobalProperty params; + params.result = NULL; + params.property = property; + params.value = value; + + return context->InvokeService(context, _OrthancPluginService_SetGlobalProperty, ¶ms); + } + + + + typedef struct + { + int32_t *resultInt32; + uint32_t *resultUint32; + int64_t *resultInt64; + uint64_t *resultUint64; + } _OrthancPluginReturnSingleValue; + + /** + * @brief Get the number of command-line arguments. + * + * Retrieve the number of command-line arguments that were used to launch Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return The number of arguments. + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetCommandLineArgumentsCount( + OrthancPluginContext* context) + { + uint32_t count = 0; + + _OrthancPluginReturnSingleValue params; + memset(¶ms, 0, sizeof(params)); + params.resultUint32 = &count; + + if (context->InvokeService(context, _OrthancPluginService_GetCommandLineArgumentsCount, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return 0; + } + else + { + return count; + } + } + + + + /** + * @brief Get the value of a command-line argument. + * + * Get the value of one of the command-line arguments that were used + * to launch Orthanc. The number of available arguments can be + * retrieved by OrthancPluginGetCommandLineArgumentsCount(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param argument The index of the argument. + * @return The value of the argument, or NULL in the case of an error. This + * string must be freed by OrthancPluginFreeString(). + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGetCommandLineArgument( + OrthancPluginContext* context, + uint32_t argument) + { + char* result; + + _OrthancPluginGlobalProperty params; + params.result = &result; + params.property = (int32_t) argument; + params.value = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetCommandLineArgument, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Get the expected version of the database schema. + * + * Retrieve the expected version of the database schema. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return The version. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetExpectedDatabaseVersion( + OrthancPluginContext* context) + { + uint32_t count = 0; + + _OrthancPluginReturnSingleValue params; + memset(¶ms, 0, sizeof(params)); + params.resultUint32 = &count; + + if (context->InvokeService(context, _OrthancPluginService_GetExpectedDatabaseVersion, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return 0; + } + else + { + return count; + } + } + + + + /** + * @brief Return the content of the configuration file(s). + * + * This function returns the content of the configuration that is + * used by Orthanc, formatted as a JSON string. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return NULL in the case of an error, or a newly allocated string + * containing the configuration. This string must be freed by + * OrthancPluginFreeString(). + **/ + ORTHANC_PLUGIN_INLINE char *OrthancPluginGetConfiguration(OrthancPluginContext* context) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetConfiguration, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + const char* subType; + const char* contentType; + } _OrthancPluginStartMultipartAnswer; + + /** + * @brief Start an HTTP multipart answer. + * + * Initiates a HTTP multipart answer, as the result of a REST request. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param subType The sub-type of the multipart answer ("mixed" or "related"). + * @param contentType The MIME type of the items in the multipart answer. + * @return 0 if success, or the error code if failure. + * @see OrthancPluginSendMultipartItem(), OrthancPluginSendMultipartItem2() + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStartMultipartAnswer( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* subType, + const char* contentType) + { + _OrthancPluginStartMultipartAnswer params; + params.output = output; + params.subType = subType; + params.contentType = contentType; + return context->InvokeService(context, _OrthancPluginService_StartMultipartAnswer, ¶ms); + } + + + /** + * @brief Send an item as a part of some HTTP multipart answer. + * + * This function sends an item as a part of some HTTP multipart + * answer that was initiated by OrthancPluginStartMultipartAnswer(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param answer Pointer to the memory buffer containing the item. + * @param answerSize Number of bytes of the item. + * @return 0 if success, or the error code if failure (this notably happens + * if the connection is closed by the client). + * @see OrthancPluginSendMultipartItem2() + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* answer, + uint32_t answerSize) + { + _OrthancPluginAnswerBuffer params; + params.output = output; + params.answer = answer; + params.answerSize = answerSize; + params.mimeType = NULL; + return context->InvokeService(context, _OrthancPluginService_SendMultipartItem, ¶ms); + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const void* source; + uint32_t size; + OrthancPluginCompressionType compression; + uint8_t uncompress; + } _OrthancPluginBufferCompression; + + + /** + * @brief Compress or decompress a buffer. + * + * This function compresses or decompresses a buffer, using the + * version of the zlib library that is used by the Orthanc core. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param source The source buffer. + * @param size The size in bytes of the source buffer. + * @param compression The compression algorithm. + * @param uncompress If set to "0", the buffer must be compressed. + * If set to "1", the buffer must be uncompressed. + * @return 0 if success, or the error code if failure. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginBufferCompression( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const void* source, + uint32_t size, + OrthancPluginCompressionType compression, + uint8_t uncompress) + { + _OrthancPluginBufferCompression params; + params.target = target; + params.source = source; + params.size = size; + params.compression = compression; + params.uncompress = uncompress; + + return context->InvokeService(context, _OrthancPluginService_BufferCompression, ¶ms); + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const char* path; + } _OrthancPluginReadFile; + + /** + * @brief Read a file. + * + * Read the content of a file on the filesystem, and returns it into + * a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param path The path of the file to be read. + * @return 0 if success, or the error code if failure. + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginReadFile( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* path) + { + _OrthancPluginReadFile params; + params.target = target; + params.path = path; + return context->InvokeService(context, _OrthancPluginService_ReadFile, ¶ms); + } + + + + typedef struct + { + const char* path; + const void* data; + uint32_t size; + } _OrthancPluginWriteFile; + + /** + * @brief Write a file. + * + * Write the content of a memory buffer to the filesystem. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param path The path of the file to be written. + * @param data The content of the memory buffer. + * @param size The size of the memory buffer. + * @return 0 if success, or the error code if failure. + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginWriteFile( + OrthancPluginContext* context, + const char* path, + const void* data, + uint32_t size) + { + _OrthancPluginWriteFile params; + params.path = path; + params.data = data; + params.size = size; + return context->InvokeService(context, _OrthancPluginService_WriteFile, ¶ms); + } + + + + typedef struct + { + const char** target; + OrthancPluginErrorCode error; + } _OrthancPluginGetErrorDescription; + + /** + * @brief Get the description of a given error code. + * + * This function returns the description of a given error code. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param error The error code of interest. + * @return The error description. This is a statically-allocated + * string, do not free it. + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetErrorDescription( + OrthancPluginContext* context, + OrthancPluginErrorCode error) + { + const char* result = NULL; + + _OrthancPluginGetErrorDescription params; + params.target = &result; + params.error = error; + + if (context->InvokeService(context, _OrthancPluginService_GetErrorDescription, ¶ms) != OrthancPluginErrorCode_Success || + result == NULL) + { + return "Unknown error code"; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + uint16_t status; + const char* body; + uint32_t bodySize; + } _OrthancPluginSendHttpStatus; + + /** + * @brief Send a HTTP status, with a custom body. + * + * This function answers to a HTTP request by sending a HTTP status + * code (such as "400 - Bad Request"), together with a body + * describing the error. The body will only be returned if the + * configuration option "HttpDescribeErrors" of Orthanc is set to "true". + * + * Note that: + * - Successful requests (status 200) must use ::OrthancPluginAnswerBuffer(). + * - Redirections (status 301) must use ::OrthancPluginRedirect(). + * - Unauthorized access (status 401) must use ::OrthancPluginSendUnauthorized(). + * - Methods not allowed (status 405) must use ::OrthancPluginSendMethodNotAllowed(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param status The HTTP status code to be sent. + * @param body The body of the answer. + * @param bodySize The size of the body. + * @see OrthancPluginSendHttpStatusCode() + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSendHttpStatus( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + uint16_t status, + const char* body, + uint32_t bodySize) + { + _OrthancPluginSendHttpStatus params; + params.output = output; + params.status = status; + params.body = body; + params.bodySize = bodySize; + context->InvokeService(context, _OrthancPluginService_SendHttpStatus, ¶ms); + } + + + + typedef struct + { + const OrthancPluginImage* image; + uint32_t* resultUint32; + OrthancPluginPixelFormat* resultPixelFormat; + void** resultBuffer; + } _OrthancPluginGetImageInfo; + + + /** + * @brief Return the pixel format of an image. + * + * This function returns the type of memory layout for the pixels of the given image. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image of interest. + * @return The pixel format. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginPixelFormat OrthancPluginGetImagePixelFormat( + OrthancPluginContext* context, + const OrthancPluginImage* image) + { + OrthancPluginPixelFormat target; + + _OrthancPluginGetImageInfo params; + memset(¶ms, 0, sizeof(params)); + params.image = image; + params.resultPixelFormat = ⌖ + + if (context->InvokeService(context, _OrthancPluginService_GetImagePixelFormat, ¶ms) != OrthancPluginErrorCode_Success) + { + return OrthancPluginPixelFormat_Unknown; + } + else + { + return (OrthancPluginPixelFormat) target; + } + } + + + + /** + * @brief Return the width of an image. + * + * This function returns the width of the given image. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image of interest. + * @return The width. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetImageWidth( + OrthancPluginContext* context, + const OrthancPluginImage* image) + { + uint32_t width; + + _OrthancPluginGetImageInfo params; + memset(¶ms, 0, sizeof(params)); + params.image = image; + params.resultUint32 = &width; + + if (context->InvokeService(context, _OrthancPluginService_GetImageWidth, ¶ms) != OrthancPluginErrorCode_Success) + { + return 0; + } + else + { + return width; + } + } + + + + /** + * @brief Return the height of an image. + * + * This function returns the height of the given image. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image of interest. + * @return The height. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetImageHeight( + OrthancPluginContext* context, + const OrthancPluginImage* image) + { + uint32_t height; + + _OrthancPluginGetImageInfo params; + memset(¶ms, 0, sizeof(params)); + params.image = image; + params.resultUint32 = &height; + + if (context->InvokeService(context, _OrthancPluginService_GetImageHeight, ¶ms) != OrthancPluginErrorCode_Success) + { + return 0; + } + else + { + return height; + } + } + + + + /** + * @brief Return the pitch of an image. + * + * This function returns the pitch of the given image. The pitch is + * defined as the number of bytes between 2 successive lines of the + * image in the memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image of interest. + * @return The pitch. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetImagePitch( + OrthancPluginContext* context, + const OrthancPluginImage* image) + { + uint32_t pitch; + + _OrthancPluginGetImageInfo params; + memset(¶ms, 0, sizeof(params)); + params.image = image; + params.resultUint32 = &pitch; + + if (context->InvokeService(context, _OrthancPluginService_GetImagePitch, ¶ms) != OrthancPluginErrorCode_Success) + { + return 0; + } + else + { + return pitch; + } + } + + + + /** + * @brief Return a pointer to the content of an image. + * + * This function returns a pointer to the memory buffer that + * contains the pixels of the image. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image of interest. + * @return The pointer. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE void* OrthancPluginGetImageBuffer( + OrthancPluginContext* context, + const OrthancPluginImage* image) + { + void* target = NULL; + + _OrthancPluginGetImageInfo params; + memset(¶ms, 0, sizeof(params)); + params.resultBuffer = ⌖ + params.image = image; + + if (context->InvokeService(context, _OrthancPluginService_GetImageBuffer, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + typedef struct + { + OrthancPluginImage** target; + const void* data; + uint32_t size; + OrthancPluginImageFormat format; + } _OrthancPluginUncompressImage; + + + /** + * @brief Decode a compressed image. + * + * This function decodes a compressed image from a memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param data Pointer to a memory buffer containing the compressed image. + * @param size Size of the memory buffer containing the compressed image. + * @param format The file format of the compressed image. + * @return The uncompressed image. It must be freed with OrthancPluginFreeImage(). + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginImage *OrthancPluginUncompressImage( + OrthancPluginContext* context, + const void* data, + uint32_t size, + OrthancPluginImageFormat format) + { + OrthancPluginImage* target = NULL; + + _OrthancPluginUncompressImage params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.data = data; + params.size = size; + params.format = format; + + if (context->InvokeService(context, _OrthancPluginService_UncompressImage, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + + + typedef struct + { + OrthancPluginImage* image; + } _OrthancPluginFreeImage; + + /** + * @brief Free an image. + * + * This function frees an image that was decoded with OrthancPluginUncompressImage(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginFreeImage( + OrthancPluginContext* context, + OrthancPluginImage* image) + { + _OrthancPluginFreeImage params; + params.image = image; + + context->InvokeService(context, _OrthancPluginService_FreeImage, ¶ms); + } + + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + OrthancPluginImageFormat imageFormat; + OrthancPluginPixelFormat pixelFormat; + uint32_t width; + uint32_t height; + uint32_t pitch; + const void* buffer; + uint8_t quality; + } _OrthancPluginCompressImage; + + + /** + * @brief Encode a PNG image. + * + * This function compresses the given memory buffer containing an + * image using the PNG specification, and stores the result of the + * compression into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param format The memory layout of the uncompressed image. + * @param width The width of the image. + * @param height The height of the image. + * @param pitch The pitch of the image (i.e. the number of bytes + * between 2 successive lines of the image in the memory buffer). + * @param buffer The memory buffer containing the uncompressed image. + * @return 0 if success, or the error code if failure. + * @see OrthancPluginCompressAndAnswerPngImage() + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCompressPngImage( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + const void* buffer) + { + _OrthancPluginCompressImage params; + memset(¶ms, 0, sizeof(params)); + params.target = target; + params.imageFormat = OrthancPluginImageFormat_Png; + params.pixelFormat = format; + params.width = width; + params.height = height; + params.pitch = pitch; + params.buffer = buffer; + params.quality = 0; /* Unused for PNG */ + + return context->InvokeService(context, _OrthancPluginService_CompressImage, ¶ms); + } + + + /** + * @brief Encode a JPEG image. + * + * This function compresses the given memory buffer containing an + * image using the JPEG specification, and stores the result of the + * compression into a newly allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param format The memory layout of the uncompressed image. + * @param width The width of the image. + * @param height The height of the image. + * @param pitch The pitch of the image (i.e. the number of bytes + * between 2 successive lines of the image in the memory buffer). + * @param buffer The memory buffer containing the uncompressed image. + * @param quality The quality of the JPEG encoding, between 1 (worst + * quality, best compression) and 100 (best quality, worst + * compression). + * @return 0 if success, or the error code if failure. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCompressJpegImage( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + const void* buffer, + uint8_t quality) + { + _OrthancPluginCompressImage params; + memset(¶ms, 0, sizeof(params)); + params.target = target; + params.imageFormat = OrthancPluginImageFormat_Jpeg; + params.pixelFormat = format; + params.width = width; + params.height = height; + params.pitch = pitch; + params.buffer = buffer; + params.quality = quality; + + return context->InvokeService(context, _OrthancPluginService_CompressImage, ¶ms); + } + + + + /** + * @brief Answer to a REST request with a JPEG image. + * + * This function answers to a REST request with a JPEG image. The + * parameters of this function describe a memory buffer that + * contains an uncompressed image. The image will be automatically compressed + * as a JPEG image by the core system of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param format The memory layout of the uncompressed image. + * @param width The width of the image. + * @param height The height of the image. + * @param pitch The pitch of the image (i.e. the number of bytes + * between 2 successive lines of the image in the memory buffer). + * @param buffer The memory buffer containing the uncompressed image. + * @param quality The quality of the JPEG encoding, between 1 (worst + * quality, best compression) and 100 (best quality, worst + * compression). + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginCompressAndAnswerJpegImage( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + const void* buffer, + uint8_t quality) + { + _OrthancPluginCompressAndAnswerImage params; + params.output = output; + params.imageFormat = OrthancPluginImageFormat_Jpeg; + params.pixelFormat = format; + params.width = width; + params.height = height; + params.pitch = pitch; + params.buffer = buffer; + params.quality = quality; + context->InvokeService(context, _OrthancPluginService_CompressAndAnswerImage, ¶ms); + } + + + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + OrthancPluginHttpMethod method; + const char* url; + const char* username; + const char* password; + const char* body; + uint32_t bodySize; + } _OrthancPluginCallHttpClient; + + + /** + * @brief Issue a HTTP GET call. + * + * Make a HTTP GET call to the given URL. The result to the query is + * stored into a newly allocated memory buffer. Favor + * OrthancPluginRestApiGet() if calling the built-in REST API of the + * Orthanc instance that hosts this plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param url The URL of interest. + * @param username The username (can be NULL if no password protection). + * @param password The password (can be NULL if no password protection). + * @return 0 if success, or the error code if failure. + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginHttpGet( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* url, + const char* username, + const char* password) + { + _OrthancPluginCallHttpClient params; + memset(¶ms, 0, sizeof(params)); + + params.target = target; + params.method = OrthancPluginHttpMethod_Get; + params.url = url; + params.username = username; + params.password = password; + + return context->InvokeService(context, _OrthancPluginService_CallHttpClient, ¶ms); + } + + + /** + * @brief Issue a HTTP POST call. + * + * Make a HTTP POST call to the given URL. The result to the query + * is stored into a newly allocated memory buffer. Favor + * OrthancPluginRestApiPost() if calling the built-in REST API of + * the Orthanc instance that hosts this plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param url The URL of interest. + * @param body The content of the body of the request. + * @param bodySize The size of the body of the request. + * @param username The username (can be NULL if no password protection). + * @param password The password (can be NULL if no password protection). + * @return 0 if success, or the error code if failure. + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginHttpPost( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* url, + const char* body, + uint32_t bodySize, + const char* username, + const char* password) + { + _OrthancPluginCallHttpClient params; + memset(¶ms, 0, sizeof(params)); + + params.target = target; + params.method = OrthancPluginHttpMethod_Post; + params.url = url; + params.body = body; + params.bodySize = bodySize; + params.username = username; + params.password = password; + + return context->InvokeService(context, _OrthancPluginService_CallHttpClient, ¶ms); + } + + + /** + * @brief Issue a HTTP PUT call. + * + * Make a HTTP PUT call to the given URL. The result to the query is + * stored into a newly allocated memory buffer. Favor + * OrthancPluginRestApiPut() if calling the built-in REST API of the + * Orthanc instance that hosts this plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param url The URL of interest. + * @param body The content of the body of the request. + * @param bodySize The size of the body of the request. + * @param username The username (can be NULL if no password protection). + * @param password The password (can be NULL if no password protection). + * @return 0 if success, or the error code if failure. + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginHttpPut( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* url, + const char* body, + uint32_t bodySize, + const char* username, + const char* password) + { + _OrthancPluginCallHttpClient params; + memset(¶ms, 0, sizeof(params)); + + params.target = target; + params.method = OrthancPluginHttpMethod_Put; + params.url = url; + params.body = body; + params.bodySize = bodySize; + params.username = username; + params.password = password; + + return context->InvokeService(context, _OrthancPluginService_CallHttpClient, ¶ms); + } + + + /** + * @brief Issue a HTTP DELETE call. + * + * Make a HTTP DELETE call to the given URL. Favor + * OrthancPluginRestApiDelete() if calling the built-in REST API of + * the Orthanc instance that hosts this plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param url The URL of interest. + * @param username The username (can be NULL if no password protection). + * @param password The password (can be NULL if no password protection). + * @return 0 if success, or the error code if failure. + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginHttpDelete( + OrthancPluginContext* context, + const char* url, + const char* username, + const char* password) + { + _OrthancPluginCallHttpClient params; + memset(¶ms, 0, sizeof(params)); + + params.method = OrthancPluginHttpMethod_Delete; + params.url = url; + params.username = username; + params.password = password; + + return context->InvokeService(context, _OrthancPluginService_CallHttpClient, ¶ms); + } + + + + typedef struct + { + OrthancPluginImage** target; + const OrthancPluginImage* source; + OrthancPluginPixelFormat targetFormat; + } _OrthancPluginConvertPixelFormat; + + + /** + * @brief Change the pixel format of an image. + * + * This function creates a new image, changing the memory layout of the pixels. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param source The source image. + * @param targetFormat The target pixel format. + * @return The resulting image. It must be freed with OrthancPluginFreeImage(). + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginImage *OrthancPluginConvertPixelFormat( + OrthancPluginContext* context, + const OrthancPluginImage* source, + OrthancPluginPixelFormat targetFormat) + { + OrthancPluginImage* target = NULL; + + _OrthancPluginConvertPixelFormat params; + params.target = ⌖ + params.source = source; + params.targetFormat = targetFormat; + + if (context->InvokeService(context, _OrthancPluginService_ConvertPixelFormat, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + + /** + * @brief Return the number of available fonts. + * + * This function returns the number of fonts that are built in the + * Orthanc core. These fonts can be used to draw texts on images + * through OrthancPluginDrawText(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return The number of fonts. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetFontsCount( + OrthancPluginContext* context) + { + uint32_t count = 0; + + _OrthancPluginReturnSingleValue params; + memset(¶ms, 0, sizeof(params)); + params.resultUint32 = &count; + + if (context->InvokeService(context, _OrthancPluginService_GetFontsCount, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return 0; + } + else + { + return count; + } + } + + + + + typedef struct + { + uint32_t fontIndex; /* in */ + const char** name; /* out */ + uint32_t* size; /* out */ + } _OrthancPluginGetFontInfo; + + /** + * @brief Return the name of a font. + * + * This function returns the name of a font that is built in the Orthanc core. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param fontIndex The index of the font. This value must be less than OrthancPluginGetFontsCount(). + * @return The font name. This is a statically-allocated string, do not free it. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetFontName( + OrthancPluginContext* context, + uint32_t fontIndex) + { + const char* result = NULL; + + _OrthancPluginGetFontInfo params; + memset(¶ms, 0, sizeof(params)); + params.name = &result; + params.fontIndex = fontIndex; + + if (context->InvokeService(context, _OrthancPluginService_GetFontInfo, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Return the size of a font. + * + * This function returns the size of a font that is built in the Orthanc core. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param fontIndex The index of the font. This value must be less than OrthancPluginGetFontsCount(). + * @return The font size. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetFontSize( + OrthancPluginContext* context, + uint32_t fontIndex) + { + uint32_t result; + + _OrthancPluginGetFontInfo params; + memset(¶ms, 0, sizeof(params)); + params.size = &result; + params.fontIndex = fontIndex; + + if (context->InvokeService(context, _OrthancPluginService_GetFontInfo, ¶ms) != OrthancPluginErrorCode_Success) + { + return 0; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginImage* image; + uint32_t fontIndex; + const char* utf8Text; + int32_t x; + int32_t y; + uint8_t r; + uint8_t g; + uint8_t b; + } _OrthancPluginDrawText; + + + /** + * @brief Draw text on an image. + * + * This function draws some text on some image. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param image The image upon which to draw the text. + * @param fontIndex The index of the font. This value must be less than OrthancPluginGetFontsCount(). + * @param utf8Text The text to be drawn, encoded as an UTF-8 zero-terminated string. + * @param x The X position of the text over the image. + * @param y The Y position of the text over the image. + * @param r The value of the red color channel of the text. + * @param g The value of the green color channel of the text. + * @param b The value of the blue color channel of the text. + * @return 0 if success, other value if error. + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginDrawText( + OrthancPluginContext* context, + OrthancPluginImage* image, + uint32_t fontIndex, + const char* utf8Text, + int32_t x, + int32_t y, + uint8_t r, + uint8_t g, + uint8_t b) + { + _OrthancPluginDrawText params; + memset(¶ms, 0, sizeof(params)); + params.image = image; + params.fontIndex = fontIndex; + params.utf8Text = utf8Text; + params.x = x; + params.y = y; + params.r = r; + params.g = g; + params.b = b; + + return context->InvokeService(context, _OrthancPluginService_DrawText, ¶ms); + } + + + + typedef struct + { + OrthancPluginStorageArea* storageArea; + const char* uuid; + const void* content; + uint64_t size; + OrthancPluginContentType type; + } _OrthancPluginStorageAreaCreate; + + + /** + * @brief Create a file inside the storage area. + * + * This function creates a new file inside the storage area that is + * currently used by Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param storageArea The storage area. + * @param uuid The identifier of the file to be created. + * @param content The content to store in the newly created file. + * @param size The size of the content. + * @param type The type of the file content. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStorageAreaCreate( + OrthancPluginContext* context, + OrthancPluginStorageArea* storageArea, + const char* uuid, + const void* content, + uint64_t size, + OrthancPluginContentType type) + { + _OrthancPluginStorageAreaCreate params; + params.storageArea = storageArea; + params.uuid = uuid; + params.content = content; + params.size = size; + params.type = type; + + return context->InvokeService(context, _OrthancPluginService_StorageAreaCreate, ¶ms); + } + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + OrthancPluginStorageArea* storageArea; + const char* uuid; + OrthancPluginContentType type; + } _OrthancPluginStorageAreaRead; + + + /** + * @brief Read a file from the storage area. + * + * This function reads the content of a given file from the storage + * area that is currently used by Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param storageArea The storage area. + * @param uuid The identifier of the file to be read. + * @param type The type of the file content. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStorageAreaRead( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + OrthancPluginStorageArea* storageArea, + const char* uuid, + OrthancPluginContentType type) + { + _OrthancPluginStorageAreaRead params; + params.target = target; + params.storageArea = storageArea; + params.uuid = uuid; + params.type = type; + + return context->InvokeService(context, _OrthancPluginService_StorageAreaRead, ¶ms); + } + + + typedef struct + { + OrthancPluginStorageArea* storageArea; + const char* uuid; + OrthancPluginContentType type; + } _OrthancPluginStorageAreaRemove; + + /** + * @brief Remove a file from the storage area. + * + * This function removes a given file from the storage area that is + * currently used by Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param storageArea The storage area. + * @param uuid The identifier of the file to be removed. + * @param type The type of the file content. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStorageAreaRemove( + OrthancPluginContext* context, + OrthancPluginStorageArea* storageArea, + const char* uuid, + OrthancPluginContentType type) + { + _OrthancPluginStorageAreaRemove params; + params.storageArea = storageArea; + params.uuid = uuid; + params.type = type; + + return context->InvokeService(context, _OrthancPluginService_StorageAreaRemove, ¶ms); + } + + + + typedef struct + { + OrthancPluginErrorCode* target; + int32_t code; + uint16_t httpStatus; + const char* message; + } _OrthancPluginRegisterErrorCode; + + /** + * @brief Declare a custom error code for this plugin. + * + * This function declares a custom error code that can be generated + * by this plugin. This declaration is used to enrich the body of + * the HTTP answer in the case of an error, and to set the proper + * HTTP status code. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param code The error code that is internal to this plugin. + * @param httpStatus The HTTP status corresponding to this error. + * @param message The description of the error. + * @return The error code that has been assigned inside the Orthanc core. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterErrorCode( + OrthancPluginContext* context, + int32_t code, + uint16_t httpStatus, + const char* message) + { + OrthancPluginErrorCode target; + + _OrthancPluginRegisterErrorCode params; + params.target = ⌖ + params.code = code; + params.httpStatus = httpStatus; + params.message = message; + + if (context->InvokeService(context, _OrthancPluginService_RegisterErrorCode, ¶ms) == OrthancPluginErrorCode_Success) + { + return target; + } + else + { + /* There was an error while assigned the error. Use a generic code. */ + return OrthancPluginErrorCode_Plugin; + } + } + + + + typedef struct + { + uint16_t group; + uint16_t element; + OrthancPluginValueRepresentation vr; + const char* name; + uint32_t minMultiplicity; + uint32_t maxMultiplicity; + } _OrthancPluginRegisterDictionaryTag; + + /** + * @brief Register a new tag into the DICOM dictionary. + * + * This function declares a new public tag in the dictionary of + * DICOM tags that are known to Orthanc. This function should be + * used in the OrthancPluginInitialize() callback. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param group The group of the tag. + * @param element The element of the tag. + * @param vr The value representation of the tag. + * @param name The nickname of the tag. + * @param minMultiplicity The minimum multiplicity of the tag (must be above 0). + * @param maxMultiplicity The maximum multiplicity of the tag. A value of 0 means + * an arbitrary multiplicity ("n"). + * @return 0 if success, other value if error. + * @see OrthancPluginRegisterPrivateDictionaryTag() + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterDictionaryTag( + OrthancPluginContext* context, + uint16_t group, + uint16_t element, + OrthancPluginValueRepresentation vr, + const char* name, + uint32_t minMultiplicity, + uint32_t maxMultiplicity) + { + _OrthancPluginRegisterDictionaryTag params; + params.group = group; + params.element = element; + params.vr = vr; + params.name = name; + params.minMultiplicity = minMultiplicity; + params.maxMultiplicity = maxMultiplicity; + + return context->InvokeService(context, _OrthancPluginService_RegisterDictionaryTag, ¶ms); + } + + + + typedef struct + { + uint16_t group; + uint16_t element; + OrthancPluginValueRepresentation vr; + const char* name; + uint32_t minMultiplicity; + uint32_t maxMultiplicity; + const char* privateCreator; + } _OrthancPluginRegisterPrivateDictionaryTag; + + /** + * @brief Register a new private tag into the DICOM dictionary. + * + * This function declares a new private tag in the dictionary of + * DICOM tags that are known to Orthanc. This function should be + * used in the OrthancPluginInitialize() callback. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param group The group of the tag. + * @param element The element of the tag. + * @param vr The value representation of the tag. + * @param name The nickname of the tag. + * @param minMultiplicity The minimum multiplicity of the tag (must be above 0). + * @param maxMultiplicity The maximum multiplicity of the tag. A value of 0 means + * an arbitrary multiplicity ("n"). + * @param privateCreator The private creator of this private tag. + * @return 0 if success, other value if error. + * @see OrthancPluginRegisterDictionaryTag() + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterPrivateDictionaryTag( + OrthancPluginContext* context, + uint16_t group, + uint16_t element, + OrthancPluginValueRepresentation vr, + const char* name, + uint32_t minMultiplicity, + uint32_t maxMultiplicity, + const char* privateCreator) + { + _OrthancPluginRegisterPrivateDictionaryTag params; + params.group = group; + params.element = element; + params.vr = vr; + params.name = name; + params.minMultiplicity = minMultiplicity; + params.maxMultiplicity = maxMultiplicity; + params.privateCreator = privateCreator; + + return context->InvokeService(context, _OrthancPluginService_RegisterPrivateDictionaryTag, ¶ms); + } + + + + typedef struct + { + OrthancPluginStorageArea* storageArea; + OrthancPluginResourceType level; + } _OrthancPluginReconstructMainDicomTags; + + /** + * @brief Reconstruct the main DICOM tags. + * + * This function requests the Orthanc core to reconstruct the main + * DICOM tags of all the resources of the given type. This function + * can only be used as a part of the upgrade of a custom database + * back-end. A database transaction will be automatically setup. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param storageArea The storage area. + * @param level The type of the resources of interest. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginReconstructMainDicomTags( + OrthancPluginContext* context, + OrthancPluginStorageArea* storageArea, + OrthancPluginResourceType level) + { + _OrthancPluginReconstructMainDicomTags params; + params.level = level; + params.storageArea = storageArea; + + return context->InvokeService(context, _OrthancPluginService_ReconstructMainDicomTags, ¶ms); + } + + + typedef struct + { + char** result; + const char* instanceId; + const void* buffer; + uint32_t size; + OrthancPluginDicomToJsonFormat format; + OrthancPluginDicomToJsonFlags flags; + uint32_t maxStringLength; + } _OrthancPluginDicomToJson; + + + /** + * @brief Format a DICOM memory buffer as a JSON string. + * + * This function takes as input a memory buffer containing a DICOM + * file, and outputs a JSON string representing the tags of this + * DICOM file. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param buffer The memory buffer containing the DICOM file. + * @param size The size of the memory buffer. + * @param format The output format. + * @param flags Flags governing the output. + * @param maxStringLength The maximum length of a field. Too long fields will + * be output as "null". The 0 value means no maximum length. + * @return The NULL value if the case of an error, or the JSON + * string. This string must be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + * @see OrthancPluginDicomInstanceToJson + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginDicomBufferToJson( + OrthancPluginContext* context, + const void* buffer, + uint32_t size, + OrthancPluginDicomToJsonFormat format, + OrthancPluginDicomToJsonFlags flags, + uint32_t maxStringLength) + { + char* result; + + _OrthancPluginDicomToJson params; + memset(¶ms, 0, sizeof(params)); + params.result = &result; + params.buffer = buffer; + params.size = size; + params.format = format; + params.flags = flags; + params.maxStringLength = maxStringLength; + + if (context->InvokeService(context, _OrthancPluginService_DicomBufferToJson, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Format a DICOM instance as a JSON string. + * + * This function formats a DICOM instance that is stored in Orthanc, + * and outputs a JSON string representing the tags of this DICOM + * instance. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instanceId The Orthanc identifier of the instance. + * @param format The output format. + * @param flags Flags governing the output. + * @param maxStringLength The maximum length of a field. Too long fields will + * be output as "null". The 0 value means no maximum length. + * @return The NULL value if the case of an error, or the JSON + * string. This string must be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + * @see OrthancPluginDicomInstanceToJson + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginDicomInstanceToJson( + OrthancPluginContext* context, + const char* instanceId, + OrthancPluginDicomToJsonFormat format, + OrthancPluginDicomToJsonFlags flags, + uint32_t maxStringLength) + { + char* result; + + _OrthancPluginDicomToJson params; + memset(¶ms, 0, sizeof(params)); + params.result = &result; + params.instanceId = instanceId; + params.format = format; + params.flags = flags; + params.maxStringLength = maxStringLength; + + if (context->InvokeService(context, _OrthancPluginService_DicomInstanceToJson, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const char* uri; + uint32_t headersCount; + const char* const* headersKeys; + const char* const* headersValues; + int32_t afterPlugins; + } _OrthancPluginRestApiGet2; + + /** + * @brief Make a GET call to the Orthanc REST API, with custom HTTP headers. + * + * Make a GET call to the Orthanc REST API with extended + * parameters. The result to the query is stored into a newly + * allocated memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param uri The URI in the built-in Orthanc API. + * @param headersCount The number of HTTP headers. + * @param headersKeys Array containing the keys of the HTTP headers (can be NULL if no header). + * @param headersValues Array containing the values of the HTTP headers (can be NULL if no header). + * @param afterPlugins If 0, the built-in API of Orthanc is used. + * If 1, the API is tainted by the plugins. + * @return 0 if success, or the error code if failure. + * @see OrthancPluginRestApiGet, OrthancPluginRestApiGetAfterPlugins + * @ingroup Orthanc + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRestApiGet2( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* uri, + uint32_t headersCount, + const char* const* headersKeys, + const char* const* headersValues, + int32_t afterPlugins) + { + _OrthancPluginRestApiGet2 params; + params.target = target; + params.uri = uri; + params.headersCount = headersCount; + params.headersKeys = headersKeys; + params.headersValues = headersValues; + params.afterPlugins = afterPlugins; + + return context->InvokeService(context, _OrthancPluginService_RestApiGet2, ¶ms); + } + + + + typedef struct + { + OrthancPluginWorklistCallback callback; + } _OrthancPluginWorklistCallback; + + /** + * @brief Register a callback to handle modality worklists requests. + * + * This function registers a callback to handle C-Find SCP requests + * on modality worklists. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterWorklistCallback( + OrthancPluginContext* context, + OrthancPluginWorklistCallback callback) + { + _OrthancPluginWorklistCallback params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterWorklistCallback, ¶ms); + } + + + + typedef struct + { + OrthancPluginWorklistAnswers* answers; + const OrthancPluginWorklistQuery* query; + const void* dicom; + uint32_t size; + } _OrthancPluginWorklistAnswersOperation; + + /** + * @brief Add one answer to some modality worklist request. + * + * This function adds one worklist (encoded as a DICOM file) to the + * set of answers corresponding to some C-Find SCP request against + * modality worklists. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answers The set of answers. + * @param query The worklist query, as received by the callback. + * @param dicom The worklist to answer, encoded as a DICOM file. + * @param size The size of the DICOM file. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + * @see OrthancPluginCreateDicom() + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginWorklistAddAnswer( + OrthancPluginContext* context, + OrthancPluginWorklistAnswers* answers, + const OrthancPluginWorklistQuery* query, + const void* dicom, + uint32_t size) + { + _OrthancPluginWorklistAnswersOperation params; + params.answers = answers; + params.query = query; + params.dicom = dicom; + params.size = size; + + return context->InvokeService(context, _OrthancPluginService_WorklistAddAnswer, ¶ms); + } + + + /** + * @brief Mark the set of worklist answers as incomplete. + * + * This function marks as incomplete the set of answers + * corresponding to some C-Find SCP request against modality + * worklists. This must be used if canceling the handling of a + * request when too many answers are to be returned. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answers The set of answers. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginWorklistMarkIncomplete( + OrthancPluginContext* context, + OrthancPluginWorklistAnswers* answers) + { + _OrthancPluginWorklistAnswersOperation params; + params.answers = answers; + params.query = NULL; + params.dicom = NULL; + params.size = 0; + + return context->InvokeService(context, _OrthancPluginService_WorklistMarkIncomplete, ¶ms); + } + + + typedef struct + { + const OrthancPluginWorklistQuery* query; + const void* dicom; + uint32_t size; + int32_t* isMatch; + OrthancPluginMemoryBuffer* target; + } _OrthancPluginWorklistQueryOperation; + + /** + * @brief Test whether a worklist matches the query. + * + * This function checks whether one worklist (encoded as a DICOM + * file) matches the C-Find SCP query against modality + * worklists. This function must be called before adding the + * worklist as an answer through OrthancPluginWorklistAddAnswer(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param query The worklist query, as received by the callback. + * @param dicom The worklist to answer, encoded as a DICOM file. + * @param size The size of the DICOM file. + * @return 1 if the worklist matches the query, 0 otherwise. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE int32_t OrthancPluginWorklistIsMatch( + OrthancPluginContext* context, + const OrthancPluginWorklistQuery* query, + const void* dicom, + uint32_t size) + { + int32_t isMatch = 0; + + _OrthancPluginWorklistQueryOperation params; + params.query = query; + params.dicom = dicom; + params.size = size; + params.isMatch = &isMatch; + params.target = NULL; + + if (context->InvokeService(context, _OrthancPluginService_WorklistIsMatch, ¶ms) == OrthancPluginErrorCode_Success) + { + return isMatch; + } + else + { + /* Error: Assume non-match */ + return 0; + } + } + + + /** + * @brief Retrieve the worklist query as a DICOM file. + * + * This function retrieves the DICOM file that underlies a C-Find + * SCP query against modality worklists. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target Memory buffer where to store the DICOM file. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param query The worklist query, as received by the callback. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginWorklistGetDicomQuery( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const OrthancPluginWorklistQuery* query) + { + _OrthancPluginWorklistQueryOperation params; + params.query = query; + params.dicom = NULL; + params.size = 0; + params.isMatch = NULL; + params.target = target; + + return context->InvokeService(context, _OrthancPluginService_WorklistGetDicomQuery, ¶ms); + } + + + /** + * @brief Get the origin of a DICOM file. + * + * This function returns the origin of a DICOM instance that has been received by Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param instance The instance of interest. + * @return The origin of the instance. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginInstanceOrigin OrthancPluginGetInstanceOrigin( + OrthancPluginContext* context, + OrthancPluginDicomInstance* instance) + { + OrthancPluginInstanceOrigin origin; + + _OrthancPluginAccessDicomInstance params; + memset(¶ms, 0, sizeof(params)); + params.resultOrigin = &origin; + params.instance = instance; + + if (context->InvokeService(context, _OrthancPluginService_GetInstanceOrigin, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return OrthancPluginInstanceOrigin_Unknown; + } + else + { + return origin; + } + } + + + typedef struct + { + OrthancPluginMemoryBuffer* target; + const char* json; + const OrthancPluginImage* pixelData; + OrthancPluginCreateDicomFlags flags; + } _OrthancPluginCreateDicom; + + /** + * @brief Create a DICOM instance from a JSON string and an image. + * + * This function takes as input a string containing a JSON file + * describing the content of a DICOM instance. As an output, it + * writes the corresponding DICOM instance to a newly allocated + * memory buffer. Additionally, an image to be encoded within the + * DICOM instance can also be provided. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target The target memory buffer. It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param json The input JSON file. + * @param pixelData The image. Can be NULL, if the pixel data is encoded inside the JSON with the data URI scheme. + * @param flags Flags governing the output. + * @return 0 if success, other value if error. + * @ingroup Toolbox + * @see OrthancPluginDicomBufferToJson + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCreateDicom( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* target, + const char* json, + const OrthancPluginImage* pixelData, + OrthancPluginCreateDicomFlags flags) + { + _OrthancPluginCreateDicom params; + params.target = target; + params.json = json; + params.pixelData = pixelData; + params.flags = flags; + + return context->InvokeService(context, _OrthancPluginService_CreateDicom, ¶ms); + } + + + typedef struct + { + OrthancPluginDecodeImageCallback callback; + } _OrthancPluginDecodeImageCallback; + + /** + * @brief Register a callback to handle the decoding of DICOM images. + * + * This function registers a custom callback to the decoding of + * DICOM images, replacing the built-in decoder of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterDecodeImageCallback( + OrthancPluginContext* context, + OrthancPluginDecodeImageCallback callback) + { + _OrthancPluginDecodeImageCallback params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterDecodeImageCallback, ¶ms); + } + + + + typedef struct + { + OrthancPluginImage** target; + OrthancPluginPixelFormat format; + uint32_t width; + uint32_t height; + uint32_t pitch; + void* buffer; + const void* constBuffer; + uint32_t bufferSize; + uint32_t frameIndex; + } _OrthancPluginCreateImage; + + + /** + * @brief Create an image. + * + * This function creates an image of given size and format. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param format The format of the pixels. + * @param width The width of the image. + * @param height The height of the image. + * @return The newly allocated image. It must be freed with OrthancPluginFreeImage(). + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginImage* OrthancPluginCreateImage( + OrthancPluginContext* context, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height) + { + OrthancPluginImage* target = NULL; + + _OrthancPluginCreateImage params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.format = format; + params.width = width; + params.height = height; + + if (context->InvokeService(context, _OrthancPluginService_CreateImage, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + /** + * @brief Create an image pointing to a memory buffer. + * + * This function creates an image whose content points to a memory + * buffer managed by the plugin. Note that the buffer is directly + * accessed, no memory is allocated and no data is copied. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param format The format of the pixels. + * @param width The width of the image. + * @param height The height of the image. + * @param pitch The pitch of the image (i.e. the number of bytes + * between 2 successive lines of the image in the memory buffer). + * @param buffer The memory buffer. + * @return The newly allocated image. It must be freed with OrthancPluginFreeImage(). + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginImage* OrthancPluginCreateImageAccessor( + OrthancPluginContext* context, + OrthancPluginPixelFormat format, + uint32_t width, + uint32_t height, + uint32_t pitch, + void* buffer) + { + OrthancPluginImage* target = NULL; + + _OrthancPluginCreateImage params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.format = format; + params.width = width; + params.height = height; + params.pitch = pitch; + params.buffer = buffer; + + if (context->InvokeService(context, _OrthancPluginService_CreateImageAccessor, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + + /** + * @brief Decode one frame from a DICOM instance. + * + * This function decodes one frame of a DICOM image that is stored + * in a memory buffer. This function will give the same result as + * OrthancPluginUncompressImage() for single-frame DICOM images. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param buffer Pointer to a memory buffer containing the DICOM image. + * @param bufferSize Size of the memory buffer containing the DICOM image. + * @param frameIndex The index of the frame of interest in a multi-frame image. + * @return The uncompressed image. It must be freed with OrthancPluginFreeImage(). + * @ingroup Images + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginImage* OrthancPluginDecodeDicomImage( + OrthancPluginContext* context, + const void* buffer, + uint32_t bufferSize, + uint32_t frameIndex) + { + OrthancPluginImage* target = NULL; + + _OrthancPluginCreateImage params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.constBuffer = buffer; + params.bufferSize = bufferSize; + params.frameIndex = frameIndex; + + if (context->InvokeService(context, _OrthancPluginService_DecodeDicomImage, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + + typedef struct + { + char** result; + const void* buffer; + uint32_t size; + } _OrthancPluginComputeHash; + + /** + * @brief Compute an MD5 hash. + * + * This functions computes the MD5 cryptographic hash of the given memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param buffer The source memory buffer. + * @param size The size in bytes of the source buffer. + * @return The NULL value in case of error, or a string containing the cryptographic hash. + * This string must be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginComputeMd5( + OrthancPluginContext* context, + const void* buffer, + uint32_t size) + { + char* result; + + _OrthancPluginComputeHash params; + params.result = &result; + params.buffer = buffer; + params.size = size; + + if (context->InvokeService(context, _OrthancPluginService_ComputeMd5, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Compute a SHA-1 hash. + * + * This functions computes the SHA-1 cryptographic hash of the given memory buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param buffer The source memory buffer. + * @param size The size in bytes of the source buffer. + * @return The NULL value in case of error, or a string containing the cryptographic hash. + * This string must be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginComputeSha1( + OrthancPluginContext* context, + const void* buffer, + uint32_t size) + { + char* result; + + _OrthancPluginComputeHash params; + params.result = &result; + params.buffer = buffer; + params.size = size; + + if (context->InvokeService(context, _OrthancPluginService_ComputeSha1, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + typedef struct + { + OrthancPluginDictionaryEntry* target; + const char* name; + } _OrthancPluginLookupDictionary; + + /** + * @brief Get information about the given DICOM tag. + * + * This functions makes a lookup in the dictionary of DICOM tags + * that are known to Orthanc, and returns information about this + * tag. The tag can be specified using its human-readable name + * (e.g. "PatientName") or a set of two hexadecimal numbers + * (e.g. "0010-0020"). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param target Where to store the information about the tag. + * @param name The name of the DICOM tag. + * @return 0 if success, other value if error. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginLookupDictionary( + OrthancPluginContext* context, + OrthancPluginDictionaryEntry* target, + const char* name) + { + _OrthancPluginLookupDictionary params; + params.target = target; + params.name = name; + return context->InvokeService(context, _OrthancPluginService_LookupDictionary, ¶ms); + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + const char* answer; + uint32_t answerSize; + uint32_t headersCount; + const char* const* headersKeys; + const char* const* headersValues; + } _OrthancPluginSendMultipartItem2; + + /** + * @brief Send an item as a part of some HTTP multipart answer, with custom headers. + * + * This function sends an item as a part of some HTTP multipart + * answer that was initiated by OrthancPluginStartMultipartAnswer(). In addition to + * OrthancPluginSendMultipartItem(), this function will set HTTP header associated + * with the item. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param answer Pointer to the memory buffer containing the item. + * @param answerSize Number of bytes of the item. + * @param headersCount The number of HTTP headers. + * @param headersKeys Array containing the keys of the HTTP headers. + * @param headersValues Array containing the values of the HTTP headers. + * @return 0 if success, or the error code if failure (this notably happens + * if the connection is closed by the client). + * @see OrthancPluginSendMultipartItem() + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem2( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* answer, + uint32_t answerSize, + uint32_t headersCount, + const char* const* headersKeys, + const char* const* headersValues) + { + _OrthancPluginSendMultipartItem2 params; + params.output = output; + params.answer = answer; + params.answerSize = answerSize; + params.headersCount = headersCount; + params.headersKeys = headersKeys; + params.headersValues = headersValues; + + return context->InvokeService(context, _OrthancPluginService_SendMultipartItem2, ¶ms); + } + + + typedef struct + { + OrthancPluginIncomingHttpRequestFilter callback; + } _OrthancPluginIncomingHttpRequestFilter; + + /** + * @brief Register a callback to filter incoming HTTP requests. + * + * This function registers a custom callback to filter incoming HTTP/REST + * requests received by the HTTP server of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup Callbacks + * @deprecated Please instead use OrthancPluginRegisterIncomingHttpRequestFilter2() + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingHttpRequestFilter( + OrthancPluginContext* context, + OrthancPluginIncomingHttpRequestFilter callback) + { + _OrthancPluginIncomingHttpRequestFilter params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterIncomingHttpRequestFilter, ¶ms); + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* answerBody; + OrthancPluginMemoryBuffer* answerHeaders; + uint16_t* httpStatus; + OrthancPluginHttpMethod method; + const char* url; + uint32_t headersCount; + const char* const* headersKeys; + const char* const* headersValues; + const char* body; + uint32_t bodySize; + const char* username; + const char* password; + uint32_t timeout; + const char* certificateFile; + const char* certificateKeyFile; + const char* certificateKeyPassword; + uint8_t pkcs11; + } _OrthancPluginCallHttpClient2; + + + + /** + * @brief Issue a HTTP call with full flexibility. + * + * Make a HTTP call to the given URL. The result to the query is + * stored into a newly allocated memory buffer. The HTTP request + * will be done accordingly to the global configuration of Orthanc + * (in particular, the options "HttpProxy", "HttpTimeout", + * "HttpsVerifyPeers", "HttpsCACertificates", and "Pkcs11" will be + * taken into account). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answerBody The target memory buffer (out argument). + * It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param answerHeaders The target memory buffer for the HTTP headers in the answers (out argument). + * The answer headers are formatted as a JSON object (associative array). + * The buffer must be freed with OrthancPluginFreeMemoryBuffer(). + * This argument can be set to NULL if the plugin has no interest in the HTTP headers. + * @param httpStatus The HTTP status after the execution of the request (out argument). + * @param method HTTP method to be used. + * @param url The URL of interest. + * @param headersCount The number of HTTP headers. + * @param headersKeys Array containing the keys of the HTTP headers (can be NULL if no header). + * @param headersValues Array containing the values of the HTTP headers (can be NULL if no header). + * @param username The username (can be NULL if no password protection). + * @param password The password (can be NULL if no password protection). + * @param body The HTTP body for a POST or PUT request. + * @param bodySize The size of the body. + * @param timeout Timeout in seconds (0 for default timeout). + * @param certificateFile Path to the client certificate for HTTPS, in PEM format + * (can be NULL if no client certificate or if not using HTTPS). + * @param certificateKeyFile Path to the key of the client certificate for HTTPS, in PEM format + * (can be NULL if no client certificate or if not using HTTPS). + * @param certificateKeyPassword Password to unlock the key of the client certificate + * (can be NULL if no client certificate or if not using HTTPS). + * @param pkcs11 Enable PKCS#11 client authentication for hardware security modules and smart cards. + * @return 0 if success, or the error code if failure. + * @see OrthancPluginCallPeerApi() + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginHttpClient( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* answerBody, + OrthancPluginMemoryBuffer* answerHeaders, + uint16_t* httpStatus, + OrthancPluginHttpMethod method, + const char* url, + uint32_t headersCount, + const char* const* headersKeys, + const char* const* headersValues, + const char* body, + uint32_t bodySize, + const char* username, + const char* password, + uint32_t timeout, + const char* certificateFile, + const char* certificateKeyFile, + const char* certificateKeyPassword, + uint8_t pkcs11) + { + _OrthancPluginCallHttpClient2 params; + memset(¶ms, 0, sizeof(params)); + + params.answerBody = answerBody; + params.answerHeaders = answerHeaders; + params.httpStatus = httpStatus; + params.method = method; + params.url = url; + params.headersCount = headersCount; + params.headersKeys = headersKeys; + params.headersValues = headersValues; + params.body = body; + params.bodySize = bodySize; + params.username = username; + params.password = password; + params.timeout = timeout; + params.certificateFile = certificateFile; + params.certificateKeyFile = certificateKeyFile; + params.certificateKeyPassword = certificateKeyPassword; + params.pkcs11 = pkcs11; + + return context->InvokeService(context, _OrthancPluginService_CallHttpClient2, ¶ms); + } + + + /** + * @brief Generate an UUID. + * + * Generate a random GUID/UUID (globally unique identifier). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return NULL in the case of an error, or a newly allocated string + * containing the UUID. This string must be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGenerateUuid( + OrthancPluginContext* context) + { + char* result; + + _OrthancPluginRetrieveDynamicString params; + params.result = &result; + params.argument = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GenerateUuid, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + + typedef struct + { + OrthancPluginFindCallback callback; + } _OrthancPluginFindCallback; + + /** + * @brief Register a callback to handle C-Find requests. + * + * This function registers a callback to handle C-Find SCP requests + * that are not related to modality worklists. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterFindCallback( + OrthancPluginContext* context, + OrthancPluginFindCallback callback) + { + _OrthancPluginFindCallback params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterFindCallback, ¶ms); + } + + + typedef struct + { + OrthancPluginFindAnswers *answers; + const OrthancPluginFindQuery *query; + const void *dicom; + uint32_t size; + uint32_t index; + uint32_t *resultUint32; + uint16_t *resultGroup; + uint16_t *resultElement; + char **resultString; + } _OrthancPluginFindOperation; + + /** + * @brief Add one answer to some C-Find request. + * + * This function adds one answer (encoded as a DICOM file) to the + * set of answers corresponding to some C-Find SCP request that is + * not related to modality worklists. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answers The set of answers. + * @param dicom The answer to be added, encoded as a DICOM file. + * @param size The size of the DICOM file. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + * @see OrthancPluginCreateDicom() + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginFindAddAnswer( + OrthancPluginContext* context, + OrthancPluginFindAnswers* answers, + const void* dicom, + uint32_t size) + { + _OrthancPluginFindOperation params; + memset(¶ms, 0, sizeof(params)); + params.answers = answers; + params.dicom = dicom; + params.size = size; + + return context->InvokeService(context, _OrthancPluginService_FindAddAnswer, ¶ms); + } + + + /** + * @brief Mark the set of C-Find answers as incomplete. + * + * This function marks as incomplete the set of answers + * corresponding to some C-Find SCP request that is not related to + * modality worklists. This must be used if canceling the handling + * of a request when too many answers are to be returned. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answers The set of answers. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginFindMarkIncomplete( + OrthancPluginContext* context, + OrthancPluginFindAnswers* answers) + { + _OrthancPluginFindOperation params; + memset(¶ms, 0, sizeof(params)); + params.answers = answers; + + return context->InvokeService(context, _OrthancPluginService_FindMarkIncomplete, ¶ms); + } + + + + /** + * @brief Get the number of tags in a C-Find query. + * + * This function returns the number of tags that are contained in + * the given C-Find query. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param query The C-Find query. + * @return The number of tags. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetFindQuerySize( + OrthancPluginContext* context, + const OrthancPluginFindQuery* query) + { + uint32_t count = 0; + + _OrthancPluginFindOperation params; + memset(¶ms, 0, sizeof(params)); + params.query = query; + params.resultUint32 = &count; + + if (context->InvokeService(context, _OrthancPluginService_GetFindQuerySize, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return 0; + } + else + { + return count; + } + } + + + /** + * @brief Get one tag in a C-Find query. + * + * This function returns the group and the element of one DICOM tag + * in the given C-Find query. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param group The group of the tag (output). + * @param element The element of the tag (output). + * @param query The C-Find query. + * @param index The index of the tag of interest. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginGetFindQueryTag( + OrthancPluginContext* context, + uint16_t* group, + uint16_t* element, + const OrthancPluginFindQuery* query, + uint32_t index) + { + _OrthancPluginFindOperation params; + memset(¶ms, 0, sizeof(params)); + params.query = query; + params.index = index; + params.resultGroup = group; + params.resultElement = element; + + return context->InvokeService(context, _OrthancPluginService_GetFindQueryTag, ¶ms); + } + + + /** + * @brief Get the symbolic name of one tag in a C-Find query. + * + * This function returns the symbolic name of one DICOM tag in the + * given C-Find query. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param query The C-Find query. + * @param index The index of the tag of interest. + * @return The NULL value in case of error, or a string containing the name of the tag. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGetFindQueryTagName( + OrthancPluginContext* context, + const OrthancPluginFindQuery* query, + uint32_t index) + { + char* result; + + _OrthancPluginFindOperation params; + memset(¶ms, 0, sizeof(params)); + params.query = query; + params.index = index; + params.resultString = &result; + + if (context->InvokeService(context, _OrthancPluginService_GetFindQueryTagName, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + /** + * @brief Get the value associated with one tag in a C-Find query. + * + * This function returns the value associated with one tag in the + * given C-Find query. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param query The C-Find query. + * @param index The index of the tag of interest. + * @return The NULL value in case of error, or a string containing the value of the tag. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginGetFindQueryValue( + OrthancPluginContext* context, + const OrthancPluginFindQuery* query, + uint32_t index) + { + char* result; + + _OrthancPluginFindOperation params; + memset(¶ms, 0, sizeof(params)); + params.query = query; + params.index = index; + params.resultString = &result; + + if (context->InvokeService(context, _OrthancPluginService_GetFindQueryValue, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + + typedef struct + { + OrthancPluginMoveCallback callback; + OrthancPluginGetMoveSize getMoveSize; + OrthancPluginApplyMove applyMove; + OrthancPluginFreeMove freeMove; + } _OrthancPluginMoveCallback; + + /** + * @brief Register a callback to handle C-Move requests. + * + * This function registers a callback to handle C-Move SCP requests. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The main callback. + * @param getMoveSize Callback to read the number of C-Move suboperations. + * @param applyMove Callback to apply one C-Move suboperations. + * @param freeMove Callback to free the C-Move driver. + * @return 0 if success, other value if error. + * @ingroup DicomCallbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterMoveCallback( + OrthancPluginContext* context, + OrthancPluginMoveCallback callback, + OrthancPluginGetMoveSize getMoveSize, + OrthancPluginApplyMove applyMove, + OrthancPluginFreeMove freeMove) + { + _OrthancPluginMoveCallback params; + params.callback = callback; + params.getMoveSize = getMoveSize; + params.applyMove = applyMove; + params.freeMove = freeMove; + + return context->InvokeService(context, _OrthancPluginService_RegisterMoveCallback, ¶ms); + } + + + + typedef struct + { + OrthancPluginFindMatcher** target; + const void* query; + uint32_t size; + } _OrthancPluginCreateFindMatcher; + + + /** + * @brief Create a C-Find matcher. + * + * This function creates a "matcher" object that can be used to + * check whether a DICOM instance matches a C-Find query. The C-Find + * query must be expressed as a DICOM buffer. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param query The C-Find DICOM query. + * @param size The size of the DICOM query. + * @return The newly allocated matcher. It must be freed with OrthancPluginFreeFindMatcher(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginFindMatcher* OrthancPluginCreateFindMatcher( + OrthancPluginContext* context, + const void* query, + uint32_t size) + { + OrthancPluginFindMatcher* target = NULL; + + _OrthancPluginCreateFindMatcher params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.query = query; + params.size = size; + + if (context->InvokeService(context, _OrthancPluginService_CreateFindMatcher, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return target; + } + } + + + typedef struct + { + OrthancPluginFindMatcher* matcher; + } _OrthancPluginFreeFindMatcher; + + /** + * @brief Free a C-Find matcher. + * + * This function frees a matcher that was created using OrthancPluginCreateFindMatcher(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param matcher The matcher of interest. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginFreeFindMatcher( + OrthancPluginContext* context, + OrthancPluginFindMatcher* matcher) + { + _OrthancPluginFreeFindMatcher params; + params.matcher = matcher; + + context->InvokeService(context, _OrthancPluginService_FreeFindMatcher, ¶ms); + } + + + typedef struct + { + const OrthancPluginFindMatcher* matcher; + const void* dicom; + uint32_t size; + int32_t* isMatch; + } _OrthancPluginFindMatcherIsMatch; + + /** + * @brief Test whether a DICOM instance matches a C-Find query. + * + * This function checks whether one DICOM instance matches C-Find + * matcher that was previously allocated using + * OrthancPluginCreateFindMatcher(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param matcher The matcher of interest. + * @param dicom The DICOM instance to be matched. + * @param size The size of the DICOM instance. + * @return 1 if the DICOM instance matches the query, 0 otherwise. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE int32_t OrthancPluginFindMatcherIsMatch( + OrthancPluginContext* context, + const OrthancPluginFindMatcher* matcher, + const void* dicom, + uint32_t size) + { + int32_t isMatch = 0; + + _OrthancPluginFindMatcherIsMatch params; + params.matcher = matcher; + params.dicom = dicom; + params.size = size; + params.isMatch = &isMatch; + + if (context->InvokeService(context, _OrthancPluginService_FindMatcherIsMatch, ¶ms) == OrthancPluginErrorCode_Success) + { + return isMatch; + } + else + { + /* Error: Assume non-match */ + return 0; + } + } + + + typedef struct + { + OrthancPluginIncomingHttpRequestFilter2 callback; + } _OrthancPluginIncomingHttpRequestFilter2; + + /** + * @brief Register a callback to filter incoming HTTP requests. + * + * This function registers a custom callback to filter incoming HTTP/REST + * requests received by the HTTP server of Orthanc. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterIncomingHttpRequestFilter2( + OrthancPluginContext* context, + OrthancPluginIncomingHttpRequestFilter2 callback) + { + _OrthancPluginIncomingHttpRequestFilter2 params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterIncomingHttpRequestFilter2, ¶ms); + } + + + + typedef struct + { + OrthancPluginPeers** peers; + } _OrthancPluginGetPeers; + + /** + * @brief Return the list of available Orthanc peers. + * + * This function returns the parameters of the Orthanc peers that are known to + * the Orthanc server hosting the plugin. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @return NULL if error, or a newly allocated opaque data structure containing the peers. + * This structure must be freed with OrthancPluginFreePeers(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginPeers* OrthancPluginGetPeers( + OrthancPluginContext* context) + { + OrthancPluginPeers* peers = NULL; + + _OrthancPluginGetPeers params; + memset(¶ms, 0, sizeof(params)); + params.peers = &peers; + + if (context->InvokeService(context, _OrthancPluginService_GetPeers, ¶ms) != OrthancPluginErrorCode_Success) + { + return NULL; + } + else + { + return peers; + } + } + + + typedef struct + { + OrthancPluginPeers* peers; + } _OrthancPluginFreePeers; + + /** + * @brief Free the list of available Orthanc peers. + * + * This function frees the data structure returned by OrthancPluginGetPeers(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param peers The data structure describing the Orthanc peers. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginFreePeers( + OrthancPluginContext* context, + OrthancPluginPeers* peers) + { + _OrthancPluginFreePeers params; + params.peers = peers; + + context->InvokeService(context, _OrthancPluginService_FreePeers, ¶ms); + } + + + typedef struct + { + uint32_t* target; + const OrthancPluginPeers* peers; + } _OrthancPluginGetPeersCount; + + /** + * @brief Get the number of Orthanc peers. + * + * This function returns the number of Orthanc peers. + * + * This function is thread-safe: Several threads sharing the same + * OrthancPluginPeers object can simultaneously call this function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param peers The data structure describing the Orthanc peers. + * @result The number of peers. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE uint32_t OrthancPluginGetPeersCount( + OrthancPluginContext* context, + const OrthancPluginPeers* peers) + { + uint32_t target = 0; + + _OrthancPluginGetPeersCount params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.peers = peers; + + if (context->InvokeService(context, _OrthancPluginService_GetPeersCount, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return 0; + } + else + { + return target; + } + } + + + typedef struct + { + const char** target; + const OrthancPluginPeers* peers; + uint32_t peerIndex; + const char* userProperty; + } _OrthancPluginGetPeerProperty; + + /** + * @brief Get the symbolic name of an Orthanc peer. + * + * This function returns the symbolic name of the Orthanc peer, + * which corresponds to the key of the "OrthancPeers" configuration + * option of Orthanc. + * + * This function is thread-safe: Several threads sharing the same + * OrthancPluginPeers object can simultaneously call this function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param peers The data structure describing the Orthanc peers. + * @param peerIndex The index of the peer of interest. + * This value must be lower than OrthancPluginGetPeersCount(). + * @result The symbolic name, or NULL in the case of an error. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerName( + OrthancPluginContext* context, + const OrthancPluginPeers* peers, + uint32_t peerIndex) + { + const char* target = NULL; + + _OrthancPluginGetPeerProperty params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.peers = peers; + params.peerIndex = peerIndex; + params.userProperty = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetPeerName, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return target; + } + } + + + /** + * @brief Get the base URL of an Orthanc peer. + * + * This function returns the base URL to the REST API of some Orthanc peer. + * + * This function is thread-safe: Several threads sharing the same + * OrthancPluginPeers object can simultaneously call this function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param peers The data structure describing the Orthanc peers. + * @param peerIndex The index of the peer of interest. + * This value must be lower than OrthancPluginGetPeersCount(). + * @result The URL, or NULL in the case of an error. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerUrl( + OrthancPluginContext* context, + const OrthancPluginPeers* peers, + uint32_t peerIndex) + { + const char* target = NULL; + + _OrthancPluginGetPeerProperty params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.peers = peers; + params.peerIndex = peerIndex; + params.userProperty = NULL; + + if (context->InvokeService(context, _OrthancPluginService_GetPeerUrl, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return target; + } + } + + + + /** + * @brief Get some user-defined property of an Orthanc peer. + * + * This function returns some user-defined property of some Orthanc + * peer. An user-defined property is a property that is associated + * with the peer in the Orthanc configuration file, but that is not + * recognized by the Orthanc core. + * + * This function is thread-safe: Several threads sharing the same + * OrthancPluginPeers object can simultaneously call this function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param peers The data structure describing the Orthanc peers. + * @param peerIndex The index of the peer of interest. + * This value must be lower than OrthancPluginGetPeersCount(). + * @param userProperty The user property of interest. + * @result The value of the user property, or NULL if it is not defined. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerUserProperty( + OrthancPluginContext* context, + const OrthancPluginPeers* peers, + uint32_t peerIndex, + const char* userProperty) + { + const char* target = NULL; + + _OrthancPluginGetPeerProperty params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.peers = peers; + params.peerIndex = peerIndex; + params.userProperty = userProperty; + + if (context->InvokeService(context, _OrthancPluginService_GetPeerUserProperty, ¶ms) != OrthancPluginErrorCode_Success) + { + /* No such user property */ + return NULL; + } + else + { + return target; + } + } + + + + typedef struct + { + OrthancPluginMemoryBuffer* answerBody; + OrthancPluginMemoryBuffer* answerHeaders; + uint16_t* httpStatus; + const OrthancPluginPeers* peers; + uint32_t peerIndex; + OrthancPluginHttpMethod method; + const char* uri; + uint32_t additionalHeadersCount; + const char* const* additionalHeadersKeys; + const char* const* additionalHeadersValues; + const char* body; + uint32_t bodySize; + uint32_t timeout; + } _OrthancPluginCallPeerApi; + + /** + * @brief Call the REST API of an Orthanc peer. + * + * Make a REST call to the given URI in the REST API of a remote + * Orthanc peer. The result to the query is stored into a newly + * allocated memory buffer. The HTTP request will be done according + * to the "OrthancPeers" configuration option of Orthanc. + * + * This function is thread-safe: Several threads sharing the same + * OrthancPluginPeers object can simultaneously call this function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param answerBody The target memory buffer (out argument). + * It must be freed with OrthancPluginFreeMemoryBuffer(). + * @param answerHeaders The target memory buffer for the HTTP headers in the answers (out argument). + * The answer headers are formatted as a JSON object (associative array). + * The buffer must be freed with OrthancPluginFreeMemoryBuffer(). + * This argument can be set to NULL if the plugin has no interest in the HTTP headers. + * @param httpStatus The HTTP status after the execution of the request (out argument). + * @param peers The data structure describing the Orthanc peers. + * @param peerIndex The index of the peer of interest. + * This value must be lower than OrthancPluginGetPeersCount(). + * @param method HTTP method to be used. + * @param uri The URI of interest in the REST API. + * @param additionalHeadersCount The number of HTTP headers to be added to the + * HTTP headers provided in the global configuration of Orthanc. + * @param additionalHeadersKeys Array containing the keys of the HTTP headers (can be NULL if no header). + * @param additionalHeadersValues Array containing the values of the HTTP headers (can be NULL if no header). + * @param body The HTTP body for a POST or PUT request. + * @param bodySize The size of the body. + * @param timeout Timeout in seconds (0 for default timeout). + * @return 0 if success, or the error code if failure. + * @see OrthancPluginHttpClient() + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginCallPeerApi( + OrthancPluginContext* context, + OrthancPluginMemoryBuffer* answerBody, + OrthancPluginMemoryBuffer* answerHeaders, + uint16_t* httpStatus, + const OrthancPluginPeers* peers, + uint32_t peerIndex, + OrthancPluginHttpMethod method, + const char* uri, + uint32_t additionalHeadersCount, + const char* const* additionalHeadersKeys, + const char* const* additionalHeadersValues, + const char* body, + uint32_t bodySize, + uint32_t timeout) + { + _OrthancPluginCallPeerApi params; + memset(¶ms, 0, sizeof(params)); + + params.answerBody = answerBody; + params.answerHeaders = answerHeaders; + params.httpStatus = httpStatus; + params.peers = peers; + params.peerIndex = peerIndex; + params.method = method; + params.uri = uri; + params.additionalHeadersCount = additionalHeadersCount; + params.additionalHeadersKeys = additionalHeadersKeys; + params.additionalHeadersValues = additionalHeadersValues; + params.body = body; + params.bodySize = bodySize; + params.timeout = timeout; + + return context->InvokeService(context, _OrthancPluginService_CallPeerApi, ¶ms); + } + + + + + + typedef struct + { + OrthancPluginJob** target; + void *job; + OrthancPluginJobFinalize finalize; + const char *type; + OrthancPluginJobGetProgress getProgress; + OrthancPluginJobGetContent getContent; + OrthancPluginJobGetSerialized getSerialized; + OrthancPluginJobStep step; + OrthancPluginJobStop stop; + OrthancPluginJobReset reset; + } _OrthancPluginCreateJob; + + /** + * @brief Create a custom job. + * + * This function creates a custom job to be run by the jobs engine + * of Orthanc. + * + * Orthanc starts one dedicated thread per custom job that is + * running. It is guaranteed that all the callbacks will only be + * called from this single dedicated thread, in mutual exclusion: As + * a consequence, it is *not* mandatory to protect the various + * callbacks by mutexes. + * + * The custom job can nonetheless launch its own processing threads + * on the first call to the "step()" callback, and stop them once + * the "stop()" callback is called. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param job The job to be executed. + * @param finalize The finalization callback. + * @param type The type of the job, provided to the job unserializer. + * See OrthancPluginRegisterJobsUnserializer(). + * @param getProgress The progress callback. + * @param getContent The content callback. + * @param getSerialized The serialization callback. + * @param step The callback to execute the individual steps of the job. + * @param stop The callback that is invoked once the job leaves the "running" state. + * @param reset The callback that is invoked if a stopped job is started again. + * @return The newly allocated job. It must be freed with OrthancPluginFreeJob(), + * as long as it is not submitted with OrthancPluginSubmitJob(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginJob *OrthancPluginCreateJob( + OrthancPluginContext *context, + void *job, + OrthancPluginJobFinalize finalize, + const char *type, + OrthancPluginJobGetProgress getProgress, + OrthancPluginJobGetContent getContent, + OrthancPluginJobGetSerialized getSerialized, + OrthancPluginJobStep step, + OrthancPluginJobStop stop, + OrthancPluginJobReset reset) + { + OrthancPluginJob* target = NULL; + + _OrthancPluginCreateJob params; + memset(¶ms, 0, sizeof(params)); + + params.target = ⌖ + params.job = job; + params.finalize = finalize; + params.type = type; + params.getProgress = getProgress; + params.getContent = getContent; + params.getSerialized = getSerialized; + params.step = step; + params.stop = stop; + params.reset = reset; + + if (context->InvokeService(context, _OrthancPluginService_CreateJob, ¶ms) != OrthancPluginErrorCode_Success || + target == NULL) + { + /* Error */ + return NULL; + } + else + { + return target; + } + } + + + typedef struct + { + OrthancPluginJob* job; + } _OrthancPluginFreeJob; + + /** + * @brief Free a custom job. + * + * This function frees an image that was created with OrthancPluginCreateJob(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param job The job. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginFreeJob( + OrthancPluginContext* context, + OrthancPluginJob* job) + { + _OrthancPluginFreeJob params; + params.job = job; + + context->InvokeService(context, _OrthancPluginService_FreeJob, ¶ms); + } + + + + typedef struct + { + char** resultId; + OrthancPluginJob *job; + int priority; + } _OrthancPluginSubmitJob; + + /** + * @brief Submit a new job to the jobs engine of Orthanc. + * + * This function adds the given job to the pending jobs of + * Orthanc. Orthanc will take take of freeing it by invoking the + * finalization callback provided to OrthancPluginCreateJob(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param job The job, as received by OrthancPluginCreateJob(). + * @param priority The priority of the job. + * @return ID of the newly-submitted job. This string must be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE char *OrthancPluginSubmitJob( + OrthancPluginContext *context, + OrthancPluginJob *job, + int priority) + { + char* resultId = NULL; + + _OrthancPluginSubmitJob params; + memset(¶ms, 0, sizeof(params)); + + params.resultId = &resultId; + params.job = job; + params.priority = priority; + + if (context->InvokeService(context, _OrthancPluginService_SubmitJob, ¶ms) != OrthancPluginErrorCode_Success || + resultId == NULL) + { + /* Error */ + return NULL; + } + else + { + return resultId; + } + } + + + + typedef struct + { + OrthancPluginJobsUnserializer unserializer; + } _OrthancPluginJobsUnserializer; + + /** + * @brief Register an unserializer for custom jobs. + * + * This function registers an unserializer that decodes custom jobs + * from a JSON string. This callback is invoked when the jobs engine + * of Orthanc is started (on Orthanc initialization), for each job + * that is stored in the Orthanc database. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param unserializer The job unserializer. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterJobsUnserializer( + OrthancPluginContext* context, + OrthancPluginJobsUnserializer unserializer) + { + _OrthancPluginJobsUnserializer params; + params.unserializer = unserializer; + + context->InvokeService(context, _OrthancPluginService_RegisterJobsUnserializer, ¶ms); + } + + + + typedef struct + { + OrthancPluginRestOutput* output; + const char* details; + uint8_t log; + } _OrthancPluginSetHttpErrorDetails; + + /** + * @brief Provide a detailed description for an HTTP error. + * + * This function sets the detailed description associated with an + * HTTP error. This description will be displayed in the "Details" + * field of the JSON body of the HTTP answer. It is only taken into + * consideration if the REST callback returns an error code that is + * different from "OrthancPluginErrorCode_Success", and if the + * "HttpDescribeErrors" configuration option of Orthanc is set to + * "true". + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param output The HTTP connection to the client application. + * @param details The details of the error message. + * @param log Whether to also write the detailed error to the Orthanc logs. + * @ingroup REST + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSetHttpErrorDetails( + OrthancPluginContext* context, + OrthancPluginRestOutput* output, + const char* details, + uint8_t log) + { + _OrthancPluginSetHttpErrorDetails params; + params.output = output; + params.details = details; + params.log = log; + context->InvokeService(context, _OrthancPluginService_SetHttpErrorDetails, ¶ms); + } + + + + typedef struct + { + const char** result; + const char* argument; + } _OrthancPluginRetrieveStaticString; + + /** + * @brief Detect the MIME type of a file. + * + * This function returns the MIME type of a file by inspecting its extension. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param path Path to the file. + * @return The MIME type. This is a statically-allocated + * string, do not free it. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginAutodetectMimeType( + OrthancPluginContext* context, + const char* path) + { + const char* result = NULL; + + _OrthancPluginRetrieveStaticString params; + params.result = &result; + params.argument = path; + + if (context->InvokeService(context, _OrthancPluginService_AutodetectMimeType, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return result; + } + } + + + + typedef struct + { + const char* name; + float value; + OrthancPluginMetricsType type; + } _OrthancPluginSetMetricsValue; + + /** + * @brief Set the value of a metrics. + * + * This function sets the value of a metrics to monitor the behavior + * of the plugin through tools such as Prometheus. The values of all + * the metrics are stored within the Orthanc context. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param name The name of the metrics to be set. + * @param value The value of the metrics. + * @param type The type of the metrics. This parameter is only taken into consideration + * the first time this metrics is set. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginSetMetricsValue( + OrthancPluginContext* context, + const char* name, + float value, + OrthancPluginMetricsType type) + { + _OrthancPluginSetMetricsValue params; + params.name = name; + params.value = value; + params.type = type; + context->InvokeService(context, _OrthancPluginService_SetMetricsValue, ¶ms); + } + + + + typedef struct + { + OrthancPluginRefreshMetricsCallback callback; + } _OrthancPluginRegisterRefreshMetricsCallback; + + /** + * @brief Register a callback to refresh the metrics. + * + * This function registers a callback to refresh the metrics. The + * callback must make calls to OrthancPluginSetMetricsValue(). + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback function to handle the refresh. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE void OrthancPluginRegisterRefreshMetricsCallback( + OrthancPluginContext* context, + OrthancPluginRefreshMetricsCallback callback) + { + _OrthancPluginRegisterRefreshMetricsCallback params; + params.callback = callback; + context->InvokeService(context, _OrthancPluginService_RegisterRefreshMetricsCallback, ¶ms); + } + + + + + typedef struct + { + char** target; + const void* dicom; + uint32_t dicomSize; + OrthancPluginDicomWebBinaryCallback callback; + } _OrthancPluginEncodeDicomWeb; + + /** + * @brief Convert a DICOM instance to DICOMweb JSON. + * + * This function converts a memory buffer containing a DICOM instance, + * into its DICOMweb JSON representation. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param dicom Pointer to the DICOM instance. + * @param dicomSize Size of the DICOM instance. + * @param callback Callback to set the value of the binary tags. + * @see OrthancPluginCreateDicom() + * @return The NULL value in case of error, or the JSON document. This string must + * be freed by OrthancPluginFreeString(). + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebJson( + OrthancPluginContext* context, + const void* dicom, + uint32_t dicomSize, + OrthancPluginDicomWebBinaryCallback callback) + { + char* target = NULL; + + _OrthancPluginEncodeDicomWeb params; + params.target = ⌖ + params.dicom = dicom; + params.dicomSize = dicomSize; + params.callback = callback; + + if (context->InvokeService(context, _OrthancPluginService_EncodeDicomWebJson, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return target; + } + } + + + /** + * @brief Convert a DICOM instance to DICOMweb XML. + * + * This function converts a memory buffer containing a DICOM instance, + * into its DICOMweb XML representation. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param dicom Pointer to the DICOM instance. + * @param dicomSize Size of the DICOM instance. + * @param callback Callback to set the value of the binary tags. + * @return The NULL value in case of error, or the JSON document. This string must + * be freed by OrthancPluginFreeString(). + * @see OrthancPluginCreateDicom() + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE char* OrthancPluginEncodeDicomWebXml( + OrthancPluginContext* context, + const void* dicom, + uint32_t dicomSize, + OrthancPluginDicomWebBinaryCallback callback) + { + char* target = NULL; + + _OrthancPluginEncodeDicomWeb params; + params.target = ⌖ + params.dicom = dicom; + params.dicomSize = dicomSize; + params.callback = callback; + + if (context->InvokeService(context, _OrthancPluginService_EncodeDicomWebXml, ¶ms) != OrthancPluginErrorCode_Success) + { + /* Error */ + return NULL; + } + else + { + return target; + } + } + + +#ifdef __cplusplus +} +#endif + + +/** @} */ + diff -Nru orthanc-mysql-2.0/Resources/PostgreSQL/c_flexmember.c orthanc-mysql-3.0/Resources/PostgreSQL/c_flexmember.c --- orthanc-mysql-2.0/Resources/PostgreSQL/c_flexmember.c 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/PostgreSQL/c_flexmember.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -#include -#include -#include -struct s { int n; double d[]; }; - -int main () -{ - int m = getchar (); - struct s *p = malloc (offsetof (struct s, d) - + m * sizeof (double)); - p->d[0] = 0.0; - return p->d != (double *) NULL; -} diff -Nru orthanc-mysql-2.0/Resources/PostgreSQL/CheckTypeAlignment.cmake orthanc-mysql-3.0/Resources/PostgreSQL/CheckTypeAlignment.cmake --- orthanc-mysql-2.0/Resources/PostgreSQL/CheckTypeAlignment.cmake 1970-01-01 00:00:00.000000000 +0000 +++ orthanc-mysql-3.0/Resources/PostgreSQL/CheckTypeAlignment.cmake 2020-12-16 15:23:36.000000000 +0000 @@ -0,0 +1,29 @@ +macro(CHECK_TYPE_ALIGNMENT TYPE NAME) + if(NOT ${NAME}) + message(STATUS "Check alignment of ${TYPE}") + + set(INCLUDE_HEADERS "#include + #include + #include ") + + if(HAVE_STDINT_H) + set(INCLUDE_HEADERS "${INCLUDE_HEADERS}\n#include \n") + endif(HAVE_STDINT_H) + + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_${NAME}_alignment.c" + "${INCLUDE_HEADERS} + int main(){ + char diff; + struct foo {char a; ${TYPE} b;}; + struct foo *p = (struct foo *) malloc(sizeof(struct foo)); + diff = ((char *)&p->b) - ((char *)&p->a); + return diff;} + ") + + try_run(${NAME} COMPILE_RESULT "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/" + "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_${NAME}_alignment.c") + + message(STATUS "Check alignment of ${TYPE} - ${${NAME}}") + + endif(NOT ${NAME}) +endmacro() diff -Nru orthanc-mysql-2.0/Resources/PostgreSQL/pg_config_ext.h orthanc-mysql-3.0/Resources/PostgreSQL/pg_config_ext.h --- orthanc-mysql-2.0/Resources/PostgreSQL/pg_config_ext.h 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/PostgreSQL/pg_config_ext.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -/* - * src/include/pg_config_ext.h.in. This is generated manually, not by - * autoheader, since we want to limit which symbols get defined here. - */ - -/* Define to the name of a signed 64-bit integer type. */ -#include -#define PG_INT64_TYPE int64_t diff -Nru orthanc-mysql-2.0/Resources/PostgreSQL/PrepareCMakeConfigurationFile.py orthanc-mysql-3.0/Resources/PostgreSQL/PrepareCMakeConfigurationFile.py --- orthanc-mysql-2.0/Resources/PostgreSQL/PrepareCMakeConfigurationFile.py 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/PostgreSQL/PrepareCMakeConfigurationFile.py 2020-12-16 15:23:36.000000000 +0000 @@ -6,7 +6,7 @@ if len(sys.argv) != 3: raise Exception('Bad number of arguments') -r = re.compile(r'^#undef ([A-Z0-9_]+)$') +r = re.compile(r'^#undef ([a-zA-Z0-9_]+)$') with open(sys.argv[1], 'r') as f: with open(sys.argv[2], 'w') as g: diff -Nru orthanc-mysql-2.0/Resources/PostgreSQL/printf_archetype.c orthanc-mysql-3.0/Resources/PostgreSQL/printf_archetype.c --- orthanc-mysql-2.0/Resources/PostgreSQL/printf_archetype.c 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/PostgreSQL/printf_archetype.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -extern int -pgac_write(int ignore, const char *fmt,...) -__attribute__((format(gnu_printf, 2, 3))); -int -main () -{ - - ; - return 0; -} diff -Nru orthanc-mysql-2.0/Resources/SyncOrthancFolder.py orthanc-mysql-3.0/Resources/SyncOrthancFolder.py --- orthanc-mysql-2.0/Resources/SyncOrthancFolder.py 2019-01-23 19:14:24.000000000 +0000 +++ orthanc-mysql-3.0/Resources/SyncOrthancFolder.py 2020-12-16 15:23:36.000000000 +0000 @@ -11,15 +11,30 @@ import urllib2 TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc') -PLUGIN_SDK_VERSION = [ '0.9.5', '1.4.0', '1.5.2' ] -REPOSITORY = 'https://bitbucket.org/sjodogne/orthanc/raw' +PLUGIN_SDK_VERSION = [ '0.9.5', '1.4.0', '1.5.2', '1.5.4' ] +REPOSITORY = 'https://hg.orthanc-server.com/orthanc/raw-file' FILES = [ - 'DownloadOrthancFramework.cmake', - 'LinuxStandardBaseToolchain.cmake', - 'MinGW-W64-Toolchain32.cmake', - 'MinGW-W64-Toolchain64.cmake', - 'MinGWToolchain.cmake', + ('OrthancFramework/Resources/CMake/AutoGeneratedCode.cmake', 'CMake'), + ('OrthancFramework/Resources/CMake/Compiler.cmake', 'CMake'), + ('OrthancFramework/Resources/CMake/DownloadOrthancFramework.cmake', 'CMake'), + ('OrthancFramework/Resources/CMake/DownloadPackage.cmake', 'CMake'), + ('OrthancFramework/Resources/CMake/GoogleTestConfiguration.cmake', 'CMake'), + ('OrthancFramework/Resources/EmbedResources.py', '.'), + ('OrthancFramework/Resources/Toolchains/LinuxStandardBaseToolchain.cmake', '.'), + ('OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain32.cmake', '.'), + ('OrthancFramework/Resources/Toolchains/MinGW-W64-Toolchain64.cmake', '.'), + ('OrthancFramework/Resources/Toolchains/MinGWToolchain.cmake', '.'), + ('OrthancServer/Plugins/Samples/Common/ExportedSymbolsPlugins.list', 'Plugins'), + ('OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp', 'Plugins'), + ('OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h', 'Plugins'), + ('OrthancServer/Plugins/Samples/Common/OrthancPluginException.h', 'Plugins'), + ('OrthancServer/Plugins/Samples/Common/OrthancPluginsExports.cmake', 'Plugins'), + ('OrthancServer/Plugins/Samples/Common/VersionScriptPlugins.map', 'Plugins'), + ('OrthancServer/Sources/Search/DatabaseConstraint.cpp', 'Databases'), + ('OrthancServer/Sources/Search/DatabaseConstraint.h', 'Databases'), + ('OrthancServer/Sources/Search/ISqlLookupFormatter.cpp', 'Databases'), + ('OrthancServer/Sources/Search/ISqlLookupFormatter.h', 'Databases'), ] SDK = [ @@ -49,8 +64,8 @@ for f in FILES: commands.append([ 'default', - os.path.join('Resources', f), - f ]) + f[0], + os.path.join(f[1], os.path.basename(f[0])) ]) for version in PLUGIN_SDK_VERSION: for f in SDK: