Orthanc-0.7.2/.hg_archival.txt0000644000000000000000000000023312237177136014341 0ustar 00000000000000repo: 3959d33612ccaadc0d4d707227fbed09ac35e5fe node: 2d59a8b9bb8407fa1f275cd05a3b625b4bd5a65f branch: Orthanc-0.7.2 latesttag: null latesttagdistance: 574 Orthanc-0.7.2/AUTHORS0000644000000000000000000000140512237177136012325 0ustar 00000000000000Orthanc - A Lightweight, RESTful DICOM Server ============================================= Authors of Orthanc ------------------ * Sebastien Jodogne Department of Medical Physics, CHU of Liege, Belgium Overall design and main developper. Client library -------------- The client library of Orthanc is automatically wrapped from the C++ code using the LAAW software. LAAW is the Lightweight, Automated API Wrapper from the Jomago team, that comes from the following authors: * Sebastien Jodogne * Alain Mazy * Benjamin Golinvaux LAAW should be soon released as a separate open-source project. Contributors ------------ See the file "THANKS" for the occasional contributors. Orthanc-0.7.2/CMakeLists.txt0000644000000000000000000003574112237177136014027 0ustar 00000000000000cmake_minimum_required(VERSION 2.8) project(Orthanc) # Version of the build, should always be "mainline" except in release branches set(ORTHANC_VERSION "0.7.2") ##################################################################### ## CMake parameters tunable at the command line ##################################################################### # Parameters of the build 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)") SET(ENABLE_SSL ON CACHE BOOL "Include support for SSL") SET(BUILD_CLIENT_LIBRARY ON CACHE BOOL "Build the client library") SET(DCMTK_DICTIONARY_DIR "/usr/share/dcmtk" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") # Advanced parameters to fine-tune linking against system libraries SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") SET(USE_SYSTEM_GOOGLE_LOG ON CACHE BOOL "Use the system version of Google Log") SET(USE_SYSTEM_GOOGLE_TEST ON CACHE BOOL "Use the system version of Google Test") SET(USE_SYSTEM_SQLITE ON CACHE BOOL "Use the system version of SQLite") SET(USE_SYSTEM_MONGOOSE ON CACHE BOOL "Use the system version of Mongoose") SET(USE_SYSTEM_LUA ON CACHE BOOL "Use the system version of Lua") SET(USE_SYSTEM_DCMTK ON CACHE BOOL "Use the system version of DCMTK") SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of Boost") SET(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of LibPng") SET(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl") # Distribution-specific settings SET(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)") mark_as_advanced(USE_GTEST_DEBIAN_SOURCE_PACKAGE) # Some basic inclusions include(CheckIncludeFiles) include(CheckIncludeFileCXX) include(CheckLibraryExists) include(${CMAKE_SOURCE_DIR}/Resources/CMake/AutoGeneratedCode.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/DownloadPackage.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/Compiler.cmake) set(ORTHANC_ROOT ${CMAKE_SOURCE_DIR}) ##################################################################### ## Inclusion of third-party dependencies ##################################################################### # Configuration of the standalone builds if (CMAKE_CROSSCOMPILING) # Cross-compilation implies the standalone build SET(STANDALONE_BUILD ON) endif() # Prepare the third-party dependencies SET(THIRD_PARTY_SOURCES ${CMAKE_SOURCE_DIR}/Resources/md5/md5.c ${CMAKE_SOURCE_DIR}/Resources/base64/base64.cpp ) include(${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleLogConfiguration.cmake) if (${ENABLE_SSL}) add_definitions(-DORTHANC_SSL_ENABLED=1) include(${CMAKE_SOURCE_DIR}/Resources/CMake/OpenSslConfiguration.cmake) else() add_definitions(-DORTHANC_SSL_ENABLED=0) endif() include(${CMAKE_SOURCE_DIR}/Resources/CMake/BoostConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/DcmtkConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/MongooseConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/ZlibConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/SQLiteConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/JsonCppConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibCurlConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibPngConfiguration.cmake) include(${CMAKE_SOURCE_DIR}/Resources/CMake/LuaConfiguration.cmake) ##################################################################### ## Autogeneration of files ##################################################################### # Prepare the embedded files set(EMBEDDED_FILES PREPARE_DATABASE ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/PrepareDatabase.sql CONFIGURATION_SAMPLE ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Configuration.json LUA_TOOLBOX ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Toolbox.lua ) if (${STANDALONE_BUILD}) # We embed all the resources in the binaries for standalone builds add_definitions(-DORTHANC_STANDALONE=1) EmbedResources( ${EMBEDDED_FILES} ORTHANC_EXPLORER ${CMAKE_CURRENT_SOURCE_DIR}/OrthancExplorer ${DCMTK_DICTIONARIES} ) else() add_definitions( -DORTHANC_STANDALONE=0 -DORTHANC_PATH=\"${CMAKE_SOURCE_DIR}\" ) EmbedResources( ${EMBEDDED_FILES} ) endif() ##################################################################### ## Build the core of Orthanc ##################################################################### add_definitions( -DORTHANC_VERSION="${ORTHANC_VERSION}" ) list(LENGTH OPENSSL_SOURCES OPENSSL_SOURCES_LENGTH) if (${OPENSSL_SOURCES_LENGTH} GREATER 0) add_library(OpenSSL STATIC ${OPENSSL_SOURCES}) endif() add_library(CoreLibrary STATIC ${AUTOGENERATED_SOURCES} ${THIRD_PARTY_SOURCES} ${CURL_SOURCES} Core/Cache/MemoryCache.cpp Core/ChunkedBuffer.cpp Core/Compression/BufferCompressor.cpp Core/Compression/ZlibCompressor.cpp Core/Compression/ZipWriter.cpp Core/Compression/HierarchicalZipWriter.cpp Core/OrthancException.cpp Core/DicomFormat/DicomArray.cpp Core/DicomFormat/DicomMap.cpp Core/DicomFormat/DicomTag.cpp Core/DicomFormat/DicomIntegerPixelAccessor.cpp Core/DicomFormat/DicomInstanceHasher.cpp Core/Enumerations.cpp Core/FileStorage/FileStorage.cpp Core/FileStorage/StorageAccessor.cpp Core/FileStorage/CompressedFileStorageAccessor.cpp Core/FileStorage/FileStorageAccessor.cpp Core/HttpClient.cpp Core/HttpServer/EmbeddedResourceHttpHandler.cpp Core/HttpServer/FilesystemHttpHandler.cpp Core/HttpServer/HttpHandler.cpp Core/HttpServer/HttpOutput.cpp Core/HttpServer/MongooseServer.cpp Core/HttpServer/HttpFileSender.cpp Core/HttpServer/FilesystemHttpSender.cpp Core/RestApi/RestApiPath.cpp Core/RestApi/RestApiOutput.cpp Core/RestApi/RestApi.cpp Core/MultiThreading/BagOfRunnablesBySteps.cpp Core/MultiThreading/SharedMessageQueue.cpp Core/MultiThreading/ThreadedCommandProcessor.cpp Core/MultiThreading/ArrayFilledByThreads.cpp Core/FileFormats/PngReader.cpp Core/FileFormats/PngWriter.cpp Core/SQLite/Connection.cpp Core/SQLite/FunctionContext.cpp Core/SQLite/Statement.cpp Core/SQLite/StatementId.cpp Core/SQLite/StatementReference.cpp Core/SQLite/Transaction.cpp Core/Toolbox.cpp Core/Uuid.cpp Core/Lua/LuaContext.cpp Core/Lua/LuaFunctionCall.cpp OrthancCppClient/OrthancConnection.cpp OrthancCppClient/Study.cpp OrthancCppClient/Series.cpp OrthancCppClient/Instance.cpp OrthancCppClient/Patient.cpp ) ##################################################################### ## Build the Orthanc server ##################################################################### add_library(ServerLibrary STATIC ${DCMTK_SOURCES} OrthancServer/DicomProtocol/DicomFindAnswers.cpp OrthancServer/DicomProtocol/DicomServer.cpp OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/Internals/CommandDispatcher.cpp OrthancServer/Internals/FindScp.cpp OrthancServer/Internals/MoveScp.cpp OrthancServer/Internals/StoreScp.cpp OrthancServer/OrthancInitialization.cpp OrthancServer/OrthancRestApi.cpp OrthancServer/ServerIndex.cpp OrthancServer/ToDcmtkBridge.cpp OrthancServer/DatabaseWrapper.cpp OrthancServer/ServerContext.cpp OrthancServer/ServerEnumerations.cpp OrthancServer/ServerToolbox.cpp OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/OrthancMoveRequestHandler.cpp ) # Ensure autogenerated code is built before building ServerLibrary add_dependencies(ServerLibrary CoreLibrary) add_executable(Orthanc OrthancServer/main.cpp ) target_link_libraries(Orthanc ServerLibrary CoreLibrary) if (${OPENSSL_SOURCES_LENGTH} GREATER 0) target_link_libraries(Orthanc OpenSSL) endif() install( TARGETS Orthanc RUNTIME DESTINATION sbin ) ##################################################################### ## Build the unit tests ##################################################################### add_definitions(-DORTHANC_BUILD_UNIT_TESTS=1) include(${CMAKE_SOURCE_DIR}/Resources/CMake/GoogleTestConfiguration.cmake) add_executable(UnitTests ${GTEST_SOURCES} UnitTestsSources/FileStorage.cpp UnitTestsSources/MemoryCache.cpp UnitTestsSources/Png.cpp UnitTestsSources/RestApi.cpp UnitTestsSources/SQLite.cpp UnitTestsSources/SQLiteChromium.cpp UnitTestsSources/ServerIndex.cpp UnitTestsSources/Versions.cpp UnitTestsSources/Zip.cpp UnitTestsSources/Lua.cpp UnitTestsSources/main.cpp ) target_link_libraries(UnitTests ServerLibrary CoreLibrary) if (${OPENSSL_SOURCES_LENGTH} GREATER 0) target_link_libraries(UnitTests OpenSSL) endif() ##################################################################### ## Create the standalone DLL containing the Orthanc Client API ##################################################################### if (BUILD_CLIENT_LIBRARY) include_directories(${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/Laaw) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if (CMAKE_CROSSCOMPILING) # Remove the default "lib" prefix from "libOrthancClient.dll" if cross-compiling set(CMAKE_SHARED_LIBRARY_PREFIX "") if (${CMAKE_SIZEOF_VOID_P} EQUAL 4) set(ORTHANC_CPP_CLIENT_AUX ${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows32.def) elseif (${CMAKE_SIZEOF_VOID_P} EQUAL 8) set(ORTHANC_CPP_CLIENT_AUX ${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows64.def) else() message(FATAL_ERROR "Support your platform here") endif() else() # Nothing to do if using Visual Studio endif() if (${CMAKE_SIZEOF_VOID_P} EQUAL 4) set(CMAKE_SHARED_LIBRARY_SUFFIX "_Windows32.dll") list(APPEND ORTHANC_CPP_CLIENT_AUX ${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows32.rc) elseif (${CMAKE_SIZEOF_VOID_P} EQUAL 8) set(CMAKE_SHARED_LIBRARY_SUFFIX "_Windows64.dll") list(APPEND ORTHANC_CPP_CLIENT_AUX ${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows64.rc) else() message(FATAL_ERROR "Support your platform here") endif() else() set(ORTHANC_CPP_CLIENT_AUX ${OPENSSL_SOURCES}) endif() add_library(OrthancClient SHARED ${ORTHANC_ROOT}/Core/OrthancException.cpp ${ORTHANC_ROOT}/Core/Enumerations.cpp ${ORTHANC_ROOT}/Core/Toolbox.cpp ${ORTHANC_ROOT}/Core/HttpClient.cpp ${ORTHANC_ROOT}/Core/MultiThreading/ArrayFilledByThreads.cpp ${ORTHANC_ROOT}/Core/MultiThreading/ThreadedCommandProcessor.cpp ${ORTHANC_ROOT}/Core/MultiThreading/SharedMessageQueue.cpp ${ORTHANC_ROOT}/Core/FileFormats/PngReader.cpp ${ORTHANC_ROOT}/OrthancCppClient/OrthancConnection.cpp ${ORTHANC_ROOT}/OrthancCppClient/Series.cpp ${ORTHANC_ROOT}/OrthancCppClient/Study.cpp ${ORTHANC_ROOT}/OrthancCppClient/Instance.cpp ${ORTHANC_ROOT}/OrthancCppClient/Patient.cpp ${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/SharedLibrary.cpp ${ORTHANC_ROOT}/Resources/md5/md5.c ${ORTHANC_ROOT}/Resources/base64/base64.cpp ${ORTHANC_CPP_CLIENT_AUX} ${THIRD_PARTY_SOURCES} ${CURL_SOURCES} ) if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set_target_properties(OrthancClient PROPERTIES LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined -Wl,--as-needed -Wl,--version-script=${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/Laaw/VersionScript.map" ) target_link_libraries(OrthancClient pthread) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") target_link_libraries(OrthancClient OpenSSL ws2_32) if (CMAKE_CROSSCOMPILING) set_target_properties(OrthancClient PROPERTIES LINK_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--allow-multiple-definition -static-libgcc -static-libstdc++" ) endif() else() message(FATAL_ERROR "Support your platform here") endif() # Set the version of the "Orthanc Client" shared library file(STRINGS ${CMAKE_SOURCE_DIR}/OrthancCppClient/SharedLibrary/Product.json ORTHANC_CLIENT_VERSION_TMP REGEX "^[ \t]*\"Version\"[ \t]*") string(REGEX REPLACE "^.*\"([0-9]+)\\.([0-9]+)\\.([0-9]+)\"" "\\1.\\2" ORTHANC_CLIENT_VERSION ${ORTHANC_CLIENT_VERSION_TMP}) message("Setting the version of the library to ${ORTHANC_CLIENT_VERSION}") set_target_properties(OrthancClient PROPERTIES VERSION ${ORTHANC_CLIENT_VERSION} SOVERSION ${ORTHANC_CLIENT_VERSION}) install( TARGETS OrthancClient RUNTIME DESTINATION lib # Destination for Windows LIBRARY DESTINATION lib # Destination for Linux ) install( FILES ${ORTHANC_ROOT}/OrthancCppClient/SharedLibrary/AUTOGENERATED/OrthancCppClient.h DESTINATION include/orthanc ) endif() ##################################################################### ## Generate the documentation if Doxygen is present ##################################################################### find_package(Doxygen) if (DOXYGEN_FOUND) configure_file( ${CMAKE_SOURCE_DIR}/Resources/Orthanc.doxygen ${CMAKE_CURRENT_BINARY_DIR}/Orthanc.doxygen @ONLY) add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Orthanc.doxygen WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating internal documentation with Doxygen" VERBATIM ) if (BUILD_CLIENT_LIBRARY) configure_file( ${CMAKE_SOURCE_DIR}/Resources/OrthancClient.doxygen ${CMAKE_CURRENT_BINARY_DIR}/OrthancClient.doxygen @ONLY) add_custom_command(TARGET OrthancClient POST_BUILD COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancClient.doxygen WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating client documentation with Doxygen" VERBATIM ) install( DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/OrthancClientDocumentation/doc/ DESTINATION share/doc/orthanc/OrthancClient ) endif() else() message("Doxygen not found. The documentation will not be built.") endif() ##################################################################### ## Prepare the "uninstall" target ## http://www.cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F ##################################################################### configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/Resources/CMake/Uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) Orthanc-0.7.2/COPYING0000644000000000000000000010451312237177136012314 0ustar 00000000000000 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 . Orthanc-0.7.2/Core/Cache/ICachePageProvider.h0000644000000000000000000000337712237177136016757 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 { class ICachePageProvider { public: virtual ~ICachePageProvider() { } virtual IDynamicObject* Provide(const std::string& id) = 0; }; } Orthanc-0.7.2/Core/Cache/LeastRecentlyUsedIndex.h0000644000000000000000000002107012237177136017710 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../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; }; /****************************************************************** ** 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; } } Orthanc-0.7.2/Core/Cache/MemoryCache.cpp0000644000000000000000000000573712237177136016064 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "MemoryCache.h" #include // This fixes a problem in glog for recent // releases of MinGW #include namespace Orthanc { 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::auto_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) { } 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_; } } Orthanc-0.7.2/Core/Cache/MemoryCache.h0000644000000000000000000000421312237177136015515 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "LeastRecentlyUsedIndex.h" #include "ICachePageProvider.h" namespace Orthanc { /** * WARNING: This class is NOT thread-safe. **/ class MemoryCache { private: struct Page { std::string id_; std::auto_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); }; } Orthanc-0.7.2/Core/ChunkedBuffer.cpp0000644000000000000000000000471412237177136015372 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "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 char* chunkData, size_t chunkSize) { if (chunkSize == 0) { return; } assert(chunkData != NULL); chunks_.push_back(new std::string(chunkData, chunkSize)); 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(); } } Orthanc-0.7.2/Core/ChunkedBuffer.h0000644000000000000000000000401712237177136015033 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 char* chunkData, size_t chunkSize); void Flatten(std::string& result); }; } Orthanc-0.7.2/Core/Compression/BufferCompressor.cpp0000644000000000000000000000504612237177136020445 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "BufferCompressor.h" namespace Orthanc { void BufferCompressor::Compress(std::string& output, const std::vector& input) { if (input.size() > 0) Compress(output, &input[0], input.size()); else Compress(output, NULL, 0); } void BufferCompressor::Uncompress(std::string& output, const std::vector& input) { if (input.size() > 0) Uncompress(output, &input[0], input.size()); else Uncompress(output, NULL, 0); } void BufferCompressor::Compress(std::string& output, const std::string& input) { if (input.size() > 0) Compress(output, &input[0], input.size()); else Compress(output, NULL, 0); } void BufferCompressor::Uncompress(std::string& output, const std::string& input) { if (input.size() > 0) Uncompress(output, &input[0], input.size()); else Uncompress(output, NULL, 0); } } Orthanc-0.7.2/Core/Compression/BufferCompressor.h0000644000000000000000000000476212237177136020116 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 namespace Orthanc { class BufferCompressor { public: virtual ~BufferCompressor() { } 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; virtual void Compress(std::string& compressed, const std::vector& uncompressed); virtual void Uncompress(std::string& uncompressed, const std::vector& compressed); virtual void Compress(std::string& compressed, const std::string& uncompressed); virtual void Uncompress(std::string& uncompressed, const std::string& compressed); }; } Orthanc-0.7.2/Core/Compression/HierarchicalZipWriter.cpp0000644000000000000000000001106612237177136021414 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "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 < 128 && 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(); } } Orthanc-0.7.2/Core/Compression/HierarchicalZipWriter.h0000644000000000000000000000637112237177136021064 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 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 GetCurrentDirectoryPath() const; 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(); 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 OpenFile(const char* name); void OpenDirectory(const char* name); void CloseDirectory(); void Write(const char* data, size_t length) { writer_.Write(data, length); } void Write(const std::string& data) { writer_.Write(data); } }; } Orthanc-0.7.2/Core/Compression/ZipWriter.cpp0000644000000000000000000001343712237177136017121 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ #ifndef NOMINMAX #define NOMINMAX #endif #include "ZipWriter.h" #include "../../Resources/minizip/zip.h" #include #include #include "../OrthancException.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 = sinceMidnight.seconds(); // seconds after the minute - [0,59] zfi.tmz_date.tm_min = sinceMidnight.minutes(); // minutes after the hour - [0,59] zfi.tmz_date.tm_hour = 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_; }; ZipWriter::ZipWriter() : pimpl_(new PImpl) { compressionLevel_ = 6; hasFileInZip_ = false; isZip64_ = false; pimpl_->file_ = NULL; } 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("Please call SetOutputPath() before creating the file"); } hasFileInZip_ = false; if (isZip64_) { pimpl_->file_ = zipOpen64(path_.c_str(), APPEND_STATUS_CREATE); } else { pimpl_->file_ = zipOpen(path_.c_str(), APPEND_STATUS_CREATE); } if (!pimpl_->file_) { throw OrthancException(ErrorCode_CannotWriteFile); } } 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("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); } hasFileInZip_ = true; } void ZipWriter::Write(const std::string& data) { if (data.size()) { Write(&data[0], data.size()); } } void ZipWriter::Write(const char* data, size_t length) { if (!hasFileInZip_) { throw OrthancException("Call first OpenFile()"); } const size_t maxBytesInAStep = std::numeric_limits::max(); while (length > 0) { int bytes = static_cast(length <= maxBytesInAStep ? length : maxBytesInAStep); if (zipWriteInFileInZip(pimpl_->file_, data, bytes)) { throw OrthancException(ErrorCode_CannotWriteFile); } data += bytes; length -= bytes; } } } Orthanc-0.7.2/Core/Compression/ZipWriter.h0000644000000000000000000000471512237177136016565 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 #if ORTHANC_BUILD_UNIT_TESTS == 1 #include #endif namespace Orthanc { class ZipWriter { private: struct PImpl; boost::shared_ptr pimpl_; bool isZip64_; bool hasFileInZip_; 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 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 char* data, size_t length); void Write(const std::string& data); }; } Orthanc-0.7.2/Core/Compression/ZlibCompressor.cpp0000644000000000000000000001023312237177136020126 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "ZlibCompressor.h" #include #include #include #include "../OrthancException.h" namespace Orthanc { void ZlibCompressor::SetCompressionLevel(uint8_t level) { if (level >= 10) { throw OrthancException("Zlib compression level must be between 0 (no compression) and 9 (highest compression"); } compressionLevel_ = level; } void ZlibCompressor::Compress(std::string& compressed, const void* uncompressed, size_t uncompressedSize) { if (uncompressedSize == 0) { compressed.clear(); return; } uLongf compressedSize = compressBound(uncompressedSize); compressed.resize(compressedSize + sizeof(size_t)); int error = compress2 (reinterpret_cast(&compressed[0]) + sizeof(size_t), &compressedSize, const_cast(static_cast(uncompressed)), uncompressedSize, compressionLevel_); memcpy(&compressed[0], &uncompressedSize, sizeof(size_t)); if (error == Z_OK) { compressed.resize(compressedSize + sizeof(size_t)); return; } else { compressed.clear(); switch (error) { case Z_MEM_ERROR: throw OrthancException(ErrorCode_NotEnoughMemory); default: throw OrthancException(ErrorCode_InternalError); } } } void ZlibCompressor::Uncompress(std::string& uncompressed, const void* compressed, size_t compressedSize) { if (compressedSize == 0) { uncompressed.clear(); return; } if (compressedSize < sizeof(size_t)) { throw OrthancException("Zlib: The compressed buffer is ill-formed"); } size_t uncompressedLength; memcpy(&uncompressedLength, compressed, sizeof(size_t)); try { uncompressed.resize(uncompressedLength); } catch (...) { throw OrthancException("Zlib: Corrupted compressed buffer"); } uLongf tmp = uncompressedLength; int error = uncompress (reinterpret_cast(&uncompressed[0]), &tmp, reinterpret_cast(compressed) + sizeof(size_t), compressedSize - sizeof(size_t)); if (error != Z_OK) { uncompressed.clear(); switch (error) { case Z_DATA_ERROR: throw OrthancException("Zlib: Corrupted or incomplete compressed buffer"); case Z_MEM_ERROR: throw OrthancException(ErrorCode_NotEnoughMemory); default: throw OrthancException(ErrorCode_InternalError); } } } } Orthanc-0.7.2/Core/Compression/ZlibCompressor.h0000644000000000000000000000441212237177136017575 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "BufferCompressor.h" namespace Orthanc { class ZlibCompressor : public BufferCompressor { private: uint8_t compressionLevel_; public: using BufferCompressor::Compress; using BufferCompressor::Uncompress; ZlibCompressor() { compressionLevel_ = 6; } void SetCompressionLevel(uint8_t level); uint8_t GetCompressionLevel() const { return compressionLevel_; } virtual void Compress(std::string& compressed, const void* uncompressed, size_t uncompressedSize); virtual void Uncompress(std::string& uncompressed, const void* compressed, size_t compressedSize); }; } Orthanc-0.7.2/Core/DicomFormat/DicomArray.cpp0000644000000000000000000000441712237177136017115 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "DicomArray.h" #include namespace Orthanc { DicomArray::DicomArray(const DicomMap& map) { elements_.reserve(map.map_.size()); for (DicomMap::Map::const_iterator it = map.map_.begin(); it != map.map_.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(); std::string s = elements_[i]->GetValue().AsString(); printf("0x%04x 0x%04x [%s]\n", t.GetGroup(), t.GetElement(), s.c_str()); } } } Orthanc-0.7.2/Core/DicomFormat/DicomArray.h0000644000000000000000000000401312237177136016552 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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: 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; }; } Orthanc-0.7.2/Core/DicomFormat/DicomElement.h0000644000000000000000000000474312237177136017077 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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(); } }; } Orthanc-0.7.2/Core/DicomFormat/DicomInstanceHasher.cpp0000644000000000000000000000660612237177136020740 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "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 (patientId_.size() == 0 || studyUid_.size() == 0 || seriesUid_.size() == 0 || instanceUid_.size() == 0) { throw OrthancException(ErrorCode_BadFileFormat); } } DicomInstanceHasher::DicomInstanceHasher(const DicomMap& instance) { Setup(instance.GetValue(DICOM_TAG_PATIENT_ID).AsString(), instance.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(), instance.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(), instance.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString()); } 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_; } } Orthanc-0.7.2/Core/DicomFormat/DicomInstanceHasher.h0000644000000000000000000000642312237177136020402 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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(); }; } Orthanc-0.7.2/Core/DicomFormat/DicomIntegerPixelAccessor.cpp0000644000000000000000000002124212237177136022114 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ #ifndef NOMINMAX #define NOMINMAX #endif #include "DicomIntegerPixelAccessor.h" #include "../OrthancException.h" #include #include #include #include namespace Orthanc { static const DicomTag COLUMNS(0x0028, 0x0011); static const DicomTag ROWS(0x0028, 0x0010); static const DicomTag SAMPLES_PER_PIXEL(0x0028, 0x0002); static const DicomTag BITS_ALLOCATED(0x0028, 0x0100); static const DicomTag BITS_STORED(0x0028, 0x0101); static const DicomTag HIGH_BIT(0x0028, 0x0102); static const DicomTag PIXEL_REPRESENTATION(0x0028, 0x0103); static const DicomTag PLANAR_CONFIGURATION(0x0028, 0x0006); DicomIntegerPixelAccessor::DicomIntegerPixelAccessor(const DicomMap& values, const void* pixelData, size_t size) : pixelData_(pixelData), size_(size) { unsigned int bitsAllocated; unsigned int bitsStored; unsigned int highBit; unsigned int pixelRepresentation; planarConfiguration_ = 0; try { width_ = boost::lexical_cast(values.GetValue(COLUMNS).AsString()); height_ = boost::lexical_cast(values.GetValue(ROWS).AsString()); samplesPerPixel_ = boost::lexical_cast(values.GetValue(SAMPLES_PER_PIXEL).AsString()); bitsAllocated = boost::lexical_cast(values.GetValue(BITS_ALLOCATED).AsString()); bitsStored = boost::lexical_cast(values.GetValue(BITS_STORED).AsString()); highBit = boost::lexical_cast(values.GetValue(HIGH_BIT).AsString()); pixelRepresentation = boost::lexical_cast(values.GetValue(PIXEL_REPRESENTATION).AsString()); if (samplesPerPixel_ > 1) { // The "Planar Configuration" is only set when "Samples per Pixels" is greater than 1 // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.3/ planarConfiguration_ = boost::lexical_cast(values.GetValue(PLANAR_CONFIGURATION).AsString()); } } catch (boost::bad_lexical_cast) { throw OrthancException(ErrorCode_NotImplemented); } catch (OrthancException) { throw OrthancException(ErrorCode_NotImplemented); } frame_ = 0; try { numberOfFrames_ = boost::lexical_cast(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).AsString()); } catch (OrthancException) { // If the tag "NumberOfFrames" is absent, assume there is a single frame numberOfFrames_ = 1; } catch (boost::bad_lexical_cast) { throw OrthancException(ErrorCode_NotImplemented); } if ((bitsAllocated != 8 && bitsAllocated != 16 && bitsAllocated != 24 && bitsAllocated != 32) || numberOfFrames_ == 0 || (planarConfiguration_ != 0 && planarConfiguration_ != 1)) { throw OrthancException(ErrorCode_NotImplemented); } if (bitsAllocated > 32 || bitsStored >= 32) { // Not available, as the accessor internally uses int32_t values throw OrthancException(ErrorCode_NotImplemented); } if (samplesPerPixel_ == 0) { throw OrthancException(ErrorCode_NotImplemented); } bytesPerPixel_ = bitsAllocated / 8; shift_ = highBit + 1 - bitsStored; frameOffset_ = height_ * width_ * bytesPerPixel_ * samplesPerPixel_; if (numberOfFrames_ * frameOffset_ > size) { throw OrthancException(ErrorCode_BadFileFormat); } /*printf("%d %d %d %d %d %d %d %d\n", width_, height_, samplesPerPixel_, bitsAllocated, bitsStored, highBit, pixelRepresentation, numberOfFrames_);*/ if (pixelRepresentation) { // Pixels are signed mask_ = (1 << (bitsStored - 1)) - 1; signMask_ = (1 << (bitsStored - 1)); } else { // Pixels are unsigned mask_ = (1 << bitsStored) - 1; signMask_ = 0; } if (planarConfiguration_ == 0) { /** * 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_ = width_ * bytesPerPixel_ * samplesPerPixel_; } else { /** * 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_ = width_ * bytesPerPixel_; } } void DicomIntegerPixelAccessor::GetExtremeValues(int32_t& min, int32_t& max) const { if (height_ == 0 || width_ == 0) { min = max = 0; return; } min = std::numeric_limits::max(); max = std::numeric_limits::min(); for (unsigned int y = 0; y < height_; y++) { for (unsigned int x = 0; x < width_; x++) { for (unsigned int c = 0; c < 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 < width_ && y < height_ && channel < samplesPerPixel_); const uint8_t* pixel = reinterpret_cast(pixelData_) + y * rowOffset_ + frame_ * frameOffset_; // https://www.dabsoft.ch/dicom/3/C.7.6.3.1.3/ if (planarConfiguration_ == 0) { /** * 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 * bytesPerPixel_ + x * samplesPerPixel_ * bytesPerPixel_; } else { /** * 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_ % samplesPerPixel_ == 0); pixel += channel * frameOffset_ / samplesPerPixel_ + x * bytesPerPixel_; } uint32_t v; v = pixel[0]; if (bytesPerPixel_ >= 2) v = v + (static_cast(pixel[1]) << 8); if (bytesPerPixel_ >= 3) v = v + (static_cast(pixel[2]) << 16); if (bytesPerPixel_ >= 4) v = v + (static_cast(pixel[3]) << 24); v = v >> shift_; 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 >= numberOfFrames_) { throw OrthancException(ErrorCode_ParameterOutOfRange); } frame_ = frame; } } Orthanc-0.7.2/Core/DicomFormat/DicomIntegerPixelAccessor.h0000644000000000000000000000540612237177136021565 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 DicomIntegerPixelAccessor { private: unsigned int width_; unsigned int height_; unsigned int samplesPerPixel_; unsigned int numberOfFrames_; unsigned int planarConfiguration_; const void* pixelData_; size_t size_; uint8_t shift_; uint32_t signMask_; uint32_t mask_; size_t bytesPerPixel_; unsigned int frame_; size_t frameOffset_; size_t rowOffset_; public: DicomIntegerPixelAccessor(const DicomMap& values, const void* pixelData, size_t size); unsigned int GetWidth() const { return width_; } unsigned int GetHeight() const { return height_; } unsigned int GetNumberOfFrames() const { return numberOfFrames_; } unsigned int GetCurrentFrame() const { return frame_; } void SetCurrentFrame(unsigned int frame); void GetExtremeValues(int32_t& min, int32_t& max) const; unsigned int GetChannelCount() const { return samplesPerPixel_; } int32_t GetValue(unsigned int x, unsigned int y, unsigned int channel = 0) const; }; } Orthanc-0.7.2/Core/DicomFormat/DicomMap.cpp0000644000000000000000000002410012237177136016543 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "DicomMap.h" #include #include #include "DicomString.h" #include "../OrthancException.h" namespace Orthanc { static DicomTag patientTags[] = { //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 }; static DicomTag studyTags[] = { //DicomTag(0x0010, 0x1020), // PatientSize //DicomTag(0x0010, 0x1030) // PatientWeight DicomTag(0x0008, 0x0020), // StudyDate DicomTag(0x0008, 0x0030), // StudyTime DicomTag(0x0008, 0x1030), // StudyDescription DicomTag(0x0020, 0x0010), // StudyID DICOM_TAG_ACCESSION_NUMBER, DICOM_TAG_STUDY_INSTANCE_UID }; static DicomTag seriesTags[] = { //DicomTag(0x0010, 0x1080), // MilitaryRank DicomTag(0x0008, 0x0021), // SeriesDate DicomTag(0x0008, 0x0031), // SeriesTime DicomTag(0x0008, 0x0060), // Modality DicomTag(0x0008, 0x0070), // Manufacturer DicomTag(0x0008, 0x1010), // StationName DicomTag(0x0008, 0x103e), // SeriesDescription DicomTag(0x0018, 0x0015), // BodyPartExamined DicomTag(0x0018, 0x0024), // SequenceName DicomTag(0x0018, 0x1030), // ProtocolName DicomTag(0x0020, 0x0011), // SeriesNumber DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, DICOM_TAG_IMAGES_IN_ACQUISITION, DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS, DICOM_TAG_NUMBER_OF_SLICES, DICOM_TAG_NUMBER_OF_TIME_SLICES, DICOM_TAG_SERIES_INSTANCE_UID }; static DicomTag instanceTags[] = { DicomTag(0x0008, 0x0012), // InstanceCreationDate DicomTag(0x0008, 0x0013), // InstanceCreationTime DicomTag(0x0020, 0x0012), // AcquisitionNumber DICOM_TAG_IMAGE_INDEX, DICOM_TAG_INSTANCE_NUMBER, DICOM_TAG_NUMBER_OF_FRAMES, DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER, DICOM_TAG_SOP_INSTANCE_UID }; void DicomMap::SetValue(uint16_t group, uint16_t element, DicomValue* value) { DicomTag tag(group, element); Map::iterator it = map_.find(tag); if (it != map_.end()) { delete it->second; it->second = value; } else { map_.insert(std::make_pair(tag, value)); } } void DicomMap::SetValue(DicomTag tag, DicomValue* value) { SetValue(tag.GetGroup(), tag.GetElement(), value); } void DicomMap::Clear() { for (Map::iterator it = map_.begin(); it != map_.end(); ++it) { delete it->second; } map_.clear(); } void DicomMap::ExtractTags(DicomMap& result, const DicomTag* tags, size_t count) const { result.Clear(); for (unsigned int i = 0; i < count; i++) { Map::const_iterator it = map_.find(tags[i]); if (it != map_.end()) { result.SetValue(it->first, it->second->Clone()); } } } void DicomMap::ExtractPatientInformation(DicomMap& result) const { ExtractTags(result, patientTags, sizeof(patientTags) / sizeof(DicomTag)); } void DicomMap::ExtractStudyInformation(DicomMap& result) const { ExtractTags(result, studyTags, sizeof(studyTags) / sizeof(DicomTag)); } void DicomMap::ExtractSeriesInformation(DicomMap& result) const { ExtractTags(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag)); } void DicomMap::ExtractInstanceInformation(DicomMap& result) const { ExtractTags(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag)); } DicomMap* DicomMap::Clone() const { std::auto_ptr result(new DicomMap); for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it) { result->map_.insert(std::make_pair(it->first, it->second->Clone())); } return result.release(); } const DicomValue& DicomMap::GetValue(const DicomTag& tag) const { const DicomValue* value = TestAndGetValue(tag); if (value) { return *value; } else { throw OrthancException("Inexistent tag"); } } const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const { Map::const_iterator it = map_.find(tag); if (it == map_.end()) { return NULL; } else { return it->second; } } void DicomMap::Remove(const DicomTag& tag) { Map::iterator it = map_.find(tag); if (it != map_.end()) { delete it->second; map_.erase(it); } } static void SetupFindTemplate(DicomMap& result, const DicomTag* tags, size_t count) { result.Clear(); for (size_t i = 0; i < count; i++) { result.SetValue(tags[i], ""); } } void DicomMap::SetupFindPatientTemplate(DicomMap& result) { SetupFindTemplate(result, patientTags, sizeof(patientTags) / sizeof(DicomTag)); } void DicomMap::SetupFindStudyTemplate(DicomMap& result) { SetupFindTemplate(result, studyTags, sizeof(studyTags) / sizeof(DicomTag)); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); result.SetValue(DICOM_TAG_PATIENT_ID, ""); } void DicomMap::SetupFindSeriesTemplate(DicomMap& result) { SetupFindTemplate(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag)); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); result.SetValue(DICOM_TAG_PATIENT_ID, ""); result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, ""); } void DicomMap::SetupFindInstanceTemplate(DicomMap& result) { SetupFindTemplate(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag)); result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); result.SetValue(DICOM_TAG_PATIENT_ID, ""); result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, ""); result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, ""); } 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) { DicomTag *tags = NULL; size_t size; switch (level) { case ResourceType_Patient: tags = patientTags; size = sizeof(patientTags) / sizeof(DicomTag); break; case ResourceType_Study: tags = studyTags; size = sizeof(studyTags) / sizeof(DicomTag); break; case ResourceType_Series: tags = seriesTags; size = sizeof(seriesTags) / sizeof(DicomTag); break; case ResourceType_Instance: tags = instanceTags; size = sizeof(instanceTags) / sizeof(DicomTag); break; default: throw OrthancException(ErrorCode_ParameterOutOfRange); } for (size_t i = 0; i < size; i++) { if (tags[i] == 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) { DicomTag *tags = NULL; size_t size; switch (level) { case ResourceType_Patient: tags = patientTags; size = sizeof(patientTags) / sizeof(DicomTag); break; case ResourceType_Study: tags = studyTags; size = sizeof(studyTags) / sizeof(DicomTag); break; case ResourceType_Series: tags = seriesTags; size = sizeof(seriesTags) / sizeof(DicomTag); break; case ResourceType_Instance: tags = instanceTags; size = sizeof(instanceTags) / sizeof(DicomTag); break; default: throw OrthancException(ErrorCode_ParameterOutOfRange); } for (size_t i = 0; i < size; i++) { result.insert(tags[i]); } } 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); } } Orthanc-0.7.2/Core/DicomFormat/DicomMap.h0000644000000000000000000001113112237177136016210 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "DicomString.h" #include "../Enumerations.h" #include #include #include namespace Orthanc { class DicomMap : public boost::noncopyable { private: friend class DicomArray; friend class FromDcmtkBridge; friend class ToDcmtkBridge; typedef std::map Map; Map map_; // Warning: This takes the ownership of "value" void SetValue(uint16_t group, uint16_t element, DicomValue* value); void SetValue(DicomTag tag, DicomValue* value); void ExtractTags(DicomMap& source, const DicomTag* tags, size_t count) const; static void GetMainDicomTagsInternal(std::set& result, ResourceType level); public: DicomMap() { } ~DicomMap() { Clear(); } DicomMap* Clone() const; void Clear(); void SetValue(uint16_t group, uint16_t element, const DicomValue& value) { SetValue(group, element, value.Clone()); } void SetValue(const DicomTag& tag, const DicomValue& value) { SetValue(tag, value.Clone()); } void SetValue(const DicomTag& tag, const std::string& str) { SetValue(tag, new DicomString(str)); } void SetValue(uint16_t group, uint16_t element, const std::string& str) { SetValue(group, element, new DicomString(str)); } bool HasTag(uint16_t group, uint16_t element) const { return HasTag(DicomTag(group, element)); } bool HasTag(const DicomTag& tag) const { return map_.find(tag) != map_.end(); } const DicomValue& GetValue(uint16_t group, uint16_t element) const { return GetValue(DicomTag(group, element)); } const DicomValue& GetValue(const DicomTag& tag) const; const DicomValue* TestAndGetValue(uint16_t group, uint16_t element) const { return TestAndGetValue(DicomTag(group, element)); } 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); }; } Orthanc-0.7.2/Core/DicomFormat/DicomNullValue.h0000644000000000000000000000361412237177136017411 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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" namespace Orthanc { class DicomNullValue : public DicomValue { public: DicomNullValue() { } virtual DicomValue* Clone() const { return new DicomNullValue(); } virtual std::string AsString() const { return "(null)"; } virtual bool IsNull() const { return true; } }; } Orthanc-0.7.2/Core/DicomFormat/DicomString.h0000644000000000000000000000377012237177136016753 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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" namespace Orthanc { class DicomString : public DicomValue { private: std::string value_; public: DicomString(const std::string& v) : value_(v) { } DicomString(const char* v) { if (v) value_ = v; else value_ = ""; } virtual DicomValue* Clone() const { return new DicomString(value_); } virtual std::string AsString() const { return value_; } }; } Orthanc-0.7.2/Core/DicomFormat/DicomTag.cpp0000644000000000000000000000654212237177136016553 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "DicomTag.h" #include "../OrthancException.h" #include #include #include namespace Orthanc { 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); } 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"; return ""; } } Orthanc-0.7.2/Core/DicomFormat/DicomTag.h0000644000000000000000000001013512237177136016211 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 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_; } 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; friend std::ostream& operator<< (std::ostream& o, const DicomTag& tag); }; // 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_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); // The following is used for "modify" 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); // 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_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); } Orthanc-0.7.2/Core/DicomFormat/DicomValue.h0000644000000000000000000000347412237177136016562 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 namespace Orthanc { class DicomValue : public IDynamicObject { public: virtual DicomValue* Clone() const = 0; virtual std::string AsString() const = 0; virtual bool IsNull() const { return false; } }; } Orthanc-0.7.2/Core/EnumerationDictionary.h0000644000000000000000000000740512237177136016640 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 #include #include namespace Orthanc { namespace Toolbox { template class EnumerationDictionary { private: typedef std::map EnumerationToString; typedef std::map StringToEnumeration; EnumerationToString enumerationToString_; StringToEnumeration stringToEnumeration_; public: 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()) { throw OrthancException(ErrorCode_BadRequest); } // Prevent the registration of a number try { boost::lexical_cast(str); throw OrthancException(ErrorCode_BadRequest); } catch (boost::bad_lexical_cast) { // OK, the string 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 { try { int value = boost::lexical_cast(str); return static_cast(value); } catch (boost::bad_lexical_cast) { } 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; } } }; } } Orthanc-0.7.2/Core/Enumerations.cpp0000644000000000000000000001533112237177136015325 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Enumerations.h" #include "OrthancException.h" #include "Toolbox.h" namespace Orthanc { 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); } } ResourceType StringToResourceType(const char* type) { std::string s(type); Toolbox::ToUpperCase(s); if (s == "PATIENT") { return ResourceType_Patient; } else if (s == "STUDY") { return ResourceType_Study; } else if (s == "SERIES") { return ResourceType_Series; } else if (s == "INSTANCE" || s == "IMAGE") { return ResourceType_Instance; } else { throw OrthancException(ErrorCode_ParameterOutOfRange); } } } Orthanc-0.7.2/Core/Enumerations.h0000644000000000000000000001621312237177136014772 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../OrthancCppClient/SharedLibrary/Laaw/laaw.h" namespace Orthanc { enum Endianness { Endianness_Unknown, Endianness_Big, Endianness_Little }; enum ErrorCode { // Generic error codes ErrorCode_Success, ErrorCode_Custom, ErrorCode_InternalError, ErrorCode_NotImplemented, ErrorCode_ParameterOutOfRange, ErrorCode_NotEnoughMemory, ErrorCode_BadParameterType, ErrorCode_BadSequenceOfCalls, ErrorCode_InexistentItem, ErrorCode_BadRequest, ErrorCode_NetworkProtocol, // Specific error codes ErrorCode_UriSyntax, ErrorCode_InexistentFile, ErrorCode_CannotWriteFile, ErrorCode_BadFileFormat, ErrorCode_Timeout, ErrorCode_UnknownResource, ErrorCode_IncompatibleDatabaseVersion, ErrorCode_FullStorage }; /** * {summary}{The memory layout of the pixels (resp. voxels) of a 2D (resp. 3D) image.} **/ enum LAAW_API 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, /** * {summary}{Graylevel 8bpp image.} * {description}{The image is graylevel. Each pixel is unsigned and stored in one byte.} **/ PixelFormat_Grayscale8, /** * {summary}{Graylevel, unsigned 16bpp image.} * {description}{The image is graylevel. Each pixel is unsigned and stored in two bytes.} **/ PixelFormat_Grayscale16, /** * {summary}{Graylevel, signed 16bpp image.} * {description}{The image is graylevel. Each pixel is signed and stored in two bytes.} **/ PixelFormat_SignedGrayscale16 }; /** * {summary}{The extraction mode specifies the way the values of the pixels are scaled when downloading a 2D image.} **/ enum LAAW_API 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, /** * {summary}{Truncation to the [0, 255] range.} **/ ImageExtractionMode_UInt8, /** * {summary}{Truncation to the [0, 65535] range.} **/ ImageExtractionMode_UInt16, /** * {summary}{Truncation to the [-32768, 32767] range.} **/ ImageExtractionMode_Int16 }; /** * 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 }; /** * 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 { CompressionType_None = 1, CompressionType_Zlib = 2 }; enum FileContentType { FileContentType_Dicom = 1, FileContentType_Json = 2 }; enum ResourceType { ResourceType_Patient = 1, ResourceType_Study = 2, ResourceType_Series = 3, ResourceType_Instance = 4 }; const char* EnumerationToString(HttpMethod method); const char* EnumerationToString(HttpStatus status); const char* EnumerationToString(ResourceType type); ResourceType StringToResourceType(const char* type); } Orthanc-0.7.2/Core/FileFormats/PngReader.cpp0000644000000000000000000001560112237177136016736 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "PngReader.h" #include "../OrthancException.h" #include "../Toolbox.h" #include #include // For memcpy() namespace Orthanc { namespace { struct FileRabi { FILE* fp_; FileRabi(const char* filename) { fp_ = fopen(filename, "rb"); if (!fp_) { throw OrthancException(ErrorCode_InexistentFile); } } ~FileRabi() { if (fp_) fclose(fp_); } }; } 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() { width_ = 0; height_ = 0; pitch_ = 0; format_ = PixelFormat_Grayscale8; } 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); width_ = width; height_ = height; 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_Grayscale8; pitch_ = 3 * width_; } else { throw OrthancException(ErrorCode_NotImplemented); } buffer_.resize(height_ * pitch_); if (height_ == 0 || width_ == 0) { // Empty image, we are done return; } png_read_update_info(rabi.png_, rabi.info_); std::vector rows(height_); for (size_t i = 0; i < height_; i++) { rows[i] = &buffer_[0] + i * pitch_; } png_read_image(rabi.png_, &rows[0]); } void PngReader::ReadFromFile(const char* filename) { FileRabi f(filename); 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); } 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); } } Orthanc-0.7.2/Core/FileFormats/PngReader.h0000644000000000000000000000525712237177136016411 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 PngReader { private: struct PngRabi; PixelFormat format_; unsigned int width_; unsigned int height_; unsigned int pitch_; std::vector buffer_; void CheckHeader(const void* header); void Read(PngRabi& rabi); public: PngReader(); PixelFormat GetFormat() const { return format_; } unsigned int GetWidth() const { return width_; } unsigned int GetHeight() const { return height_; } unsigned int GetPitch() const { return pitch_; } const void* GetBuffer() const { if (buffer_.size() > 0) return &buffer_[0]; else return NULL; } const void* GetBuffer(unsigned int y) const { if (buffer_.size() > 0) return &buffer_[y * pitch_]; else return NULL; } void ReadFromFile(const char* filename); void ReadFromMemory(const void* buffer, size_t size); void ReadFromMemory(const std::string& buffer); }; } Orthanc-0.7.2/Core/FileFormats/PngWriter.cpp0000644000000000000000000001560312237177136017012 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "PngWriter.h" #include #include #include #include "../OrthancException.h" #include "../ChunkedBuffer.h" #include "../Toolbox.h" // 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_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); } void PngWriter::WriteToFile(const char* filename, unsigned int width, unsigned int height, unsigned int pitch, PixelFormat format, const void* buffer) { Prepare(width, height, pitch, format, buffer); FILE* fp = fopen(filename, "wb"); 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); } 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(reinterpret_cast(data), size); } void PngWriter::WriteToMemory(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); } } Orthanc-0.7.2/Core/FileFormats/PngWriter.h0000644000000000000000000000514212237177136016454 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 PngWriter { 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(); void WriteToFile(const char* filename, unsigned int width, unsigned int height, unsigned int pitch, PixelFormat format, const void* buffer); void WriteToMemory(std::string& png, unsigned int width, unsigned int height, unsigned int pitch, PixelFormat format, const void* buffer); }; } Orthanc-0.7.2/Core/FileStorage/CompressedFileStorageAccessor.cpp0000644000000000000000000000736412237177136023003 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "CompressedFileStorageAccessor.h" #include "../OrthancException.h" #include "FileStorageAccessor.h" #include "../HttpServer/BufferHttpSender.h" namespace Orthanc { FileInfo CompressedFileStorageAccessor::WriteInternal(const void* data, size_t size, FileContentType type) { switch (compressionType_) { case CompressionType_None: { std::string uuid = storage_.Create(data, size); return FileInfo(uuid, type, size); } case CompressionType_Zlib: { std::string compressed; zlib_.Compress(compressed, data, size); std::string uuid = storage_.Create(compressed); return FileInfo(uuid, type, size, CompressionType_Zlib, compressed.size()); } default: throw OrthancException(ErrorCode_NotImplemented); } } CompressedFileStorageAccessor::CompressedFileStorageAccessor(FileStorage& storage) : storage_(storage) { compressionType_ = CompressionType_None; } void CompressedFileStorageAccessor::Read(std::string& content, const std::string& uuid) { switch (compressionType_) { case CompressionType_None: storage_.ReadFile(content, uuid); break; case CompressionType_Zlib: { std::string compressed; storage_.ReadFile(compressed, uuid); zlib_.Uncompress(content, compressed); break; } default: throw OrthancException(ErrorCode_NotImplemented); } } HttpFileSender* CompressedFileStorageAccessor::ConstructHttpFileSender(const std::string& uuid) { switch (compressionType_) { case CompressionType_None: { FileStorageAccessor uncompressedAccessor(storage_); return uncompressedAccessor.ConstructHttpFileSender(uuid); } case CompressionType_Zlib: { std::string compressed; storage_.ReadFile(compressed, uuid); std::auto_ptr sender(new BufferHttpSender); zlib_.Uncompress(sender->GetBuffer(), compressed); return sender.release(); } default: throw OrthancException(ErrorCode_NotImplemented); } } } Orthanc-0.7.2/Core/FileStorage/CompressedFileStorageAccessor.h0000644000000000000000000000467512237177136022452 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "StorageAccessor.h" #include "FileStorage.h" #include "../Compression/ZlibCompressor.h" namespace Orthanc { class CompressedFileStorageAccessor : public StorageAccessor { private: FileStorage& storage_; ZlibCompressor zlib_; CompressionType compressionType_; protected: virtual FileInfo WriteInternal(const void* data, size_t size, FileContentType type); public: CompressedFileStorageAccessor(FileStorage& storage); void SetCompressionForNextOperations(CompressionType compression) { compressionType_ = compression; } CompressionType GetCompressionForNextOperations() { return compressionType_; } virtual void Read(std::string& content, const std::string& uuid); virtual HttpFileSender* ConstructHttpFileSender(const std::string& uuid); }; } Orthanc-0.7.2/Core/FileStorage/FileInfo.h0000644000000000000000000000604112237177136016216 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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_; CompressionType compressionType_; uint64_t compressedSize_; public: FileInfo() { } /** * Constructor for an uncompressed attachment. **/ FileInfo(const std::string& uuid, FileContentType contentType, uint64_t size) : uuid_(uuid), contentType_(contentType), uncompressedSize_(size), compressionType_(CompressionType_None), compressedSize_(size) { } /** * Constructor for a compressed attachment. **/ FileInfo(const std::string& uuid, FileContentType contentType, uint64_t uncompressedSize, CompressionType compressionType, uint64_t compressedSize) : uuid_(uuid), contentType_(contentType), uncompressedSize_(uncompressedSize), compressionType_(compressionType), compressedSize_(compressedSize) { } 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_; } }; } Orthanc-0.7.2/Core/FileStorage/FileStorage.cpp0000644000000000000000000002001212237177136017254 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "FileStorage.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 "../OrthancException.h" #include "../Toolbox.h" #include "../Uuid.h" #include #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 FileStorage::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; } FileStorage::FileStorage(std::string root) { namespace fs = boost::filesystem; //root_ = boost::filesystem::absolute(root).string(); root_ = root; if (fs::exists(root)) { if (!fs::is_directory(root)) { throw OrthancException("The file storage root directory is a file"); } } else { if (!fs::create_directories(root)) { throw OrthancException("Unable to create the file storage root directory"); } } } std::string FileStorage::CreateFileWithoutCompression(const void* content, size_t size) { std::string uuid; boost::filesystem::path path; for (;;) { uuid = Toolbox::GenerateUuid(); path = GetPath(uuid); if (!boost::filesystem::exists(path)) { // OK, this is indeed a new file break; } // Extremely improbable case: This Uuid has already been created // in the past. Try again. } if (boost::filesystem::exists(path.parent_path())) { if (!boost::filesystem::is_directory(path.parent_path())) { throw OrthancException("The subdirectory to be created is already occupied by a regular file"); } } else { if (!boost::filesystem::create_directories(path.parent_path())) { throw OrthancException("Unable to create a subdirectory in the file storage"); } } boost::filesystem::ofstream f; f.open(path, std::ofstream::out | std::ios::binary); if (!f.good()) { throw OrthancException("Unable to create a new file in the file storage"); } if (size != 0) { f.write(static_cast(content), size); if (!f.good()) { f.close(); throw OrthancException("Unable to write to the new file in the file storage"); } } f.close(); return uuid; } std::string FileStorage::Create(const void* content, size_t size) { if (!HasBufferCompressor() || size == 0) { return CreateFileWithoutCompression(content, size); } else { std::string compressed; compressor_->Compress(compressed, content, size); assert(compressed.size() > 0); return CreateFileWithoutCompression(&compressed[0], compressed.size()); } } std::string FileStorage::Create(const std::vector& content) { if (content.size() == 0) return Create(NULL, 0); else return Create(&content[0], content.size()); } std::string FileStorage::Create(const std::string& content) { if (content.size() == 0) return Create(NULL, 0); else return Create(&content[0], content.size()); } void FileStorage::ReadFile(std::string& content, const std::string& uuid) const { content.clear(); if (HasBufferCompressor()) { std::string compressed; Toolbox::ReadFile(compressed, ToString(GetPath(uuid))); if (compressed.size() != 0) { compressor_->Uncompress(content, compressed); } } else { Toolbox::ReadFile(content, GetPath(uuid).string()); } } uintmax_t FileStorage::GetCompressedSize(const std::string& uuid) const { boost::filesystem::path path = GetPath(uuid); return boost::filesystem::file_size(path); } void FileStorage::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 (fs::is_regular_file(current->status())) { 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 FileStorage::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); } } void FileStorage::Remove(const std::string& uuid) { LOG(INFO) << "Deleting file " << uuid; 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 FileStorage::GetCapacity() const { return boost::filesystem::space(root_).capacity; } uintmax_t FileStorage::GetAvailableSpace() const { return boost::filesystem::space(root_).available; } } Orthanc-0.7.2/Core/FileStorage/FileStorage.h0000644000000000000000000000561512237177136016735 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../Compression/BufferCompressor.h" namespace Orthanc { class FileStorage : public boost::noncopyable { // TODO REMOVE THIS friend class FilesystemHttpSender; friend class FileStorageAccessor; private: std::auto_ptr compressor_; boost::filesystem::path root_; boost::filesystem::path GetPath(const std::string& uuid) const; std::string CreateFileWithoutCompression(const void* content, size_t size); public: FileStorage(std::string root); void SetBufferCompressor(BufferCompressor* compressor) // Takes the ownership { compressor_.reset(compressor); } bool HasBufferCompressor() const { return compressor_.get() != NULL; } std::string Create(const void* content, size_t size); std::string Create(const std::vector& content); std::string Create(const std::string& content); void ReadFile(std::string& content, const std::string& uuid) const; void ListAllFiles(std::set& result) const; uintmax_t GetCompressedSize(const std::string& uuid) const; void Clear(); void Remove(const std::string& uuid); uintmax_t GetCapacity() const; uintmax_t GetAvailableSpace() const; std::string GetPath() const { return root_.string(); } }; } Orthanc-0.7.2/Core/FileStorage/FileStorageAccessor.cpp0000644000000000000000000000351112237177136020744 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "FileStorageAccessor.h" namespace Orthanc { FileInfo FileStorageAccessor::WriteInternal(const void* data, size_t size, FileContentType type) { return FileInfo(storage_.Create(data, size), type, size); } } Orthanc-0.7.2/Core/FileStorage/FileStorageAccessor.h0000644000000000000000000000445612237177136020422 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "StorageAccessor.h" #include "FileStorage.h" #include "../HttpServer/FilesystemHttpSender.h" namespace Orthanc { class FileStorageAccessor : public StorageAccessor { private: FileStorage& storage_; protected: virtual FileInfo WriteInternal(const void* data, size_t size, FileContentType type); public: FileStorageAccessor(FileStorage& storage) : storage_(storage) { } virtual void Read(std::string& content, const std::string& uuid) { storage_.ReadFile(content, uuid); } virtual HttpFileSender* ConstructHttpFileSender(const std::string& uuid) { return new FilesystemHttpSender(storage_.GetPath(uuid)); } }; } Orthanc-0.7.2/Core/FileStorage/StorageAccessor.cpp0000644000000000000000000000422612237177136020150 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "StorageAccessor.h" namespace Orthanc { FileInfo StorageAccessor::Write(const std::vector& content, FileContentType type) { if (content.size() == 0) { return WriteInternal(NULL, 0, type); } else { return WriteInternal(&content[0], content.size(), type); } } FileInfo StorageAccessor::Write(const std::string& content, FileContentType type) { if (content.size() == 0) { return WriteInternal(NULL, 0, type); } else { return WriteInternal(&content[0], content.size(), type); } } } Orthanc-0.7.2/Core/FileStorage/StorageAccessor.h0000644000000000000000000000500112237177136017605 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "FileInfo.h" #include "../HttpServer/HttpFileSender.h" #include #include #include #include namespace Orthanc { class StorageAccessor : boost::noncopyable { protected: virtual FileInfo WriteInternal(const void* data, size_t size, FileContentType type) = 0; public: virtual ~StorageAccessor() { } FileInfo Write(const void* data, size_t size, FileContentType type) { return WriteInternal(data, size, type); } FileInfo Write(const std::vector& content, FileContentType type); FileInfo Write(const std::string& content, FileContentType type); virtual void Read(std::string& content, const std::string& uuid) = 0; virtual HttpFileSender* ConstructHttpFileSender(const std::string& uuid) = 0; }; } Orthanc-0.7.2/Core/HttpClient.cpp0000644000000000000000000001542212237177136014733 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpClient.h" #include "../Core/Toolbox.h" #include "../Core/OrthancException.h" #include #include namespace Orthanc { struct HttpClient::PImpl { CURL* curl_; struct curl_slist *postHeaders_; }; static CURLcode CheckCode(CURLcode code) { if (code != CURLE_OK) { throw OrthancException("libCURL error: " + std::string(curl_easy_strerror(code))); } return code; } static size_t CurlCallback(void *buffer, size_t size, size_t nmemb, void *payload) { std::string& target = *(static_cast(payload)); size_t length = size * nmemb; if (length == 0) return 0; size_t pos = target.size(); target.resize(pos + length); memcpy(&target.at(pos), buffer, length); return length; } void HttpClient::Setup() { pimpl_->postHeaders_ = NULL; if ((pimpl_->postHeaders_ = curl_slist_append(pimpl_->postHeaders_, "Expect:")) == NULL) { throw OrthancException(ErrorCode_NotEnoughMemory); } pimpl_->curl_ = curl_easy_init(); if (!pimpl_->curl_) { curl_slist_free_all(pimpl_->postHeaders_); throw OrthancException(ErrorCode_NotEnoughMemory); } CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEFUNCTION, &CurlCallback)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADER, 0)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1)); #if ORTHANC_SSL_ENABLED == 1 CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSL_VERIFYPEER, 0)); #endif // 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_200_Ok; isVerbose_ = false; } HttpClient::HttpClient() : pimpl_(new PImpl) { Setup(); } HttpClient::HttpClient(const HttpClient& other) : pimpl_(new PImpl) { Setup(); if (other.IsVerbose()) { SetVerbose(true); } if (other.credentials_.size() != 0) { credentials_ = other.credentials_; } } HttpClient::~HttpClient() { curl_easy_cleanup(pimpl_->curl_); curl_slist_free_all(pimpl_->postHeaders_); } void HttpClient::SetVerbose(bool isVerbose) { isVerbose_ = isVerbose; if (isVerbose_) { CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_VERBOSE, 1)); } else { CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_VERBOSE, 0)); } } bool HttpClient::Apply(std::string& answer) { answer.clear(); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str())); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, NULL)); if (credentials_.size() != 0) { CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_USERPWD, credentials_.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)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, pimpl_->postHeaders_)); if (postData_.size() > 0) { CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, postData_.c_str())); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, postData_.size())); } else { CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0)); } 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: CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PUT, 1L)); break; default: throw OrthancException(ErrorCode_InternalError); } // Do the actual request CheckCode(curl_easy_perform(pimpl_->curl_)); long status; CheckCode(curl_easy_getinfo(pimpl_->curl_, CURLINFO_RESPONSE_CODE, &status)); if (status == 0) { // This corresponds to a call to an inexistent host lastStatus_ = HttpStatus_500_InternalServerError; } else { lastStatus_ = static_cast(status); } return (status >= 200 && status < 300); } bool HttpClient::Apply(Json::Value& answer) { std::string s; if (Apply(s)) { Json::Reader reader; return reader.parse(s, answer); } else { return false; } } void HttpClient::SetCredentials(const char* username, const char* password) { credentials_ = std::string(username) + ":" + std::string(password); } void HttpClient::GlobalInitialize() { CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT)); } void HttpClient::GlobalFinalize() { curl_global_cleanup(); } const char* HttpClient::GetLastStatusText() const { return EnumerationToString(lastStatus_); } } Orthanc-0.7.2/Core/HttpClient.h0000644000000000000000000000601612237177136014377 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 #include namespace Orthanc { class HttpClient { private: struct PImpl; boost::shared_ptr pimpl_; std::string url_; std::string credentials_; HttpMethod method_; HttpStatus lastStatus_; std::string postData_; bool isVerbose_; void Setup(); void operator= (const HttpClient&); // Forbidden public: HttpClient(const HttpClient& base); HttpClient(); ~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_; } std::string& AccessPostData() { return postData_; } const std::string& AccessPostData() const { return postData_; } void SetVerbose(bool isVerbose); bool IsVerbose() const { return isVerbose_; } bool Apply(std::string& answer); bool Apply(Json::Value& answer); HttpStatus GetLastStatus() const { return lastStatus_; } const char* GetLastStatusText() const; void SetCredentials(const char* username, const char* password); static void GlobalInitialize(); static void GlobalFinalize(); }; } Orthanc-0.7.2/Core/HttpServer/BufferHttpSender.h0000644000000000000000000000406612237177136017644 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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_; protected: virtual uint64_t GetFileSize() { return buffer_.size(); } virtual bool SendData(HttpOutput& output) { if (buffer_.size()) output.Send(&buffer_[0], buffer_.size()); return true; } public: std::string& GetBuffer() { return buffer_; } const std::string& GetBuffer() const { return buffer_; } }; } Orthanc-0.7.2/Core/HttpServer/EmbeddedResourceHttpHandler.cpp0000644000000000000000000000571512237177136022326 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "EmbeddedResourceHttpHandler.h" #include "../OrthancException.h" #include "HttpOutput.h" #include #include namespace Orthanc { EmbeddedResourceHttpHandler::EmbeddedResourceHttpHandler( const std::string& baseUri, EmbeddedResources::DirectoryResourceId resourceId) { Toolbox::SplitUriComponents(baseUri_, baseUri); resourceId_ = resourceId; } bool EmbeddedResourceHttpHandler::IsServedUri(const UriComponents& uri) { return Toolbox::IsChildUri(baseUri_, uri); } void EmbeddedResourceHttpHandler::Handle( HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& arguments, const std::string&) { if (method != HttpMethod_Get) { output.SendMethodNotAllowedError("GET"); return; } std::string resourcePath = Toolbox::FlattenUri(uri, baseUri_.size()); std::string contentType = Toolbox::AutodetectMimeType(resourcePath); try { const void* buffer = EmbeddedResources::GetDirectoryResourceBuffer(resourceId_, resourcePath.c_str()); size_t size = EmbeddedResources::GetDirectoryResourceSize(resourceId_, resourcePath.c_str()); output.AnswerBufferWithContentType(buffer, size, contentType); } catch (OrthancException&) { LOG(WARNING) << "Unable to find HTTP resource: " << resourcePath; output.SendHeader(HttpStatus_404_NotFound); } } } Orthanc-0.7.2/Core/HttpServer/EmbeddedResourceHttpHandler.h0000644000000000000000000000431612237177136021767 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpHandler.h" #include // Autogenerated file #include namespace Orthanc { class EmbeddedResourceHttpHandler : public HttpHandler { private: UriComponents baseUri_; EmbeddedResources::DirectoryResourceId resourceId_; public: EmbeddedResourceHttpHandler( const std::string& baseUri, EmbeddedResources::DirectoryResourceId resourceId); virtual bool IsServedUri(const UriComponents& uri); virtual void Handle( HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& arguments, const std::string&); }; } Orthanc-0.7.2/Core/HttpServer/FilesystemHttpHandler.cpp0000644000000000000000000001162612237177136021247 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "FilesystemHttpHandler.h" #include "../OrthancException.h" #include "FilesystemHttpSender.h" #include namespace Orthanc { struct FilesystemHttpHandler::PImpl { UriComponents baseUri_; boost::filesystem::path root_; }; static void OutputDirectoryContent(HttpOutput& output, const UriComponents& uri, const boost::filesystem::path& p) { namespace fs = boost::filesystem; output.SendOkHeader("text/html", false, 0, NULL); output.SendString(""); output.SendString(" "); output.SendString("

Subdirectories

"); output.SendString("
    "); if (uri.size() > 0) { std::string h = Toolbox::FlattenUri(uri) + "/.."; output.SendString("
  • ..
  • "); } 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())) output.SendString("
  • " + f + "
  • "); } output.SendString("
"); output.SendString("

Files

"); output.SendString("
    "); 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_regular_file(it->status())) output.SendString("
  • " + f + "
  • "); } output.SendString("
"); output.SendString(" "); output.SendString(""); } 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("The path does not point to a directory"); } } bool FilesystemHttpHandler::IsServedUri(const UriComponents& uri) { return Toolbox::IsChildUri(pimpl_->baseUri_, uri); } void FilesystemHttpHandler::Handle( HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& arguments, const std::string&) { if (method != HttpMethod_Get) { output.SendMethodNotAllowedError("GET"); return; } namespace fs = boost::filesystem; fs::path p = pimpl_->root_; for (size_t i = pimpl_->baseUri_.size(); i < uri.size(); i++) { p /= uri[i]; } if (fs::exists(p) && fs::is_regular_file(p)) { FilesystemHttpSender(p).Send(output); //output.AnswerFileAutodetectContentType(p.string()); } else if (listDirectoryContent_ && fs::exists(p) && fs::is_directory(p)) { OutputDirectoryContent(output, uri, p); } else { output.SendHeader(HttpStatus_404_NotFound); } } } Orthanc-0.7.2/Core/HttpServer/FilesystemHttpHandler.h0000644000000000000000000000463412237177136020715 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpHandler.h" #include namespace Orthanc { class FilesystemHttpHandler : public HttpHandler { 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 IsServedUri(const UriComponents& uri); virtual void Handle( HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& arguments, const std::string&); bool IsListDirectoryContent() const { return listDirectoryContent_; } void SetListDirectoryContent(bool enabled) { listDirectoryContent_ = enabled; } }; } Orthanc-0.7.2/Core/HttpServer/FilesystemHttpSender.cpp0000644000000000000000000000562512237177136021114 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "FilesystemHttpSender.h" #include "../Toolbox.h" #include namespace Orthanc { void FilesystemHttpSender::Setup() { //SetDownloadFilename(path_.filename().string()); #if BOOST_HAS_FILESYSTEM_V3 == 1 SetContentType(Toolbox::AutodetectMimeType(path_.filename().string())); #else SetContentType(Toolbox::AutodetectMimeType(path_.filename())); #endif } uint64_t FilesystemHttpSender::GetFileSize() { return Toolbox::GetFileSize(path_.string()); } bool FilesystemHttpSender::SendData(HttpOutput& output) { FILE* fp = fopen(path_.string().c_str(), "rb"); if (!fp) { return false; } std::vector buffer(1024 * 1024); // Chunks of 1MB for (;;) { size_t nbytes = fread(&buffer[0], 1, buffer.size(), fp); if (nbytes == 0) { break; } else { output.Send(&buffer[0], nbytes); } } fclose(fp); return true; } FilesystemHttpSender::FilesystemHttpSender(const char* path) { path_ = std::string(path); Setup(); } FilesystemHttpSender::FilesystemHttpSender(const boost::filesystem::path& path) { path_ = path; Setup(); } FilesystemHttpSender::FilesystemHttpSender(const FileStorage& storage, const std::string& uuid) { path_ = storage.GetPath(uuid).string(); Setup(); } } Orthanc-0.7.2/Core/HttpServer/FilesystemHttpSender.h0000644000000000000000000000406512237177136020556 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../FileStorage/FileStorage.h" namespace Orthanc { class FilesystemHttpSender : public HttpFileSender { private: boost::filesystem::path path_; void Setup(); protected: virtual uint64_t GetFileSize(); virtual bool SendData(HttpOutput& output); public: FilesystemHttpSender(const char* path); FilesystemHttpSender(const boost::filesystem::path& path); FilesystemHttpSender(const FileStorage& storage, const std::string& uuid); }; } Orthanc-0.7.2/Core/HttpServer/HttpFileSender.cpp0000644000000000000000000000366512237177136017651 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpFileSender.h" #include namespace Orthanc { void HttpFileSender::SendHeader(HttpOutput& output) { output.SendOkHeader(contentType_.c_str(), true, GetFileSize(), downloadFilename_.c_str()); } void HttpFileSender::Send(HttpOutput& output) { SendHeader(output); if (!SendData(output)) { output.SendHeader(HttpStatus_500_InternalServerError); } } } Orthanc-0.7.2/Core/HttpServer/HttpFileSender.h0000644000000000000000000000467612237177136017321 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 { private: std::string contentType_; std::string downloadFilename_; void SendHeader(HttpOutput& output); protected: virtual uint64_t GetFileSize() = 0; virtual bool SendData(HttpOutput& output) = 0; public: virtual ~HttpFileSender() { } void ResetContentType() { contentType_.clear(); } void SetContentType(const std::string& contentType) { contentType_ = contentType; } const std::string& GetContentType() const { return contentType_; } void ResetDownloadFilename() { downloadFilename_.clear(); } void SetDownloadFilename(const std::string& filename) { downloadFilename_ = filename; } const std::string& GetDownloadFilename() const { return downloadFilename_; } void Send(HttpOutput& output); }; } Orthanc-0.7.2/Core/HttpServer/HttpHandler.cpp0000644000000000000000000001007312237177136017175 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpHandler.h" #include namespace Orthanc { static void SplitGETNameValue(HttpHandler::Arguments& 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.insert(std::make_pair(name, value)); } void HttpHandler::ParseGetQuery(HttpHandler::Arguments& 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; } } } std::string HttpHandler::GetArgument(const Arguments& getArguments, const std::string& name, const std::string& defaultValue) { Arguments::const_iterator it = getArguments.find(name); if (it == getArguments.end()) { return defaultValue; } else { return it->second; } } void HttpHandler::ParseCookies(HttpHandler::Arguments& result, const HttpHandler::Arguments& httpHeaders) { result.clear(); HttpHandler::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; } } } } } Orthanc-0.7.2/Core/HttpServer/HttpHandler.h0000644000000000000000000000510412237177136016641 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../Toolbox.h" namespace Orthanc { class HttpOutput; class HttpHandler { public: typedef std::map Arguments; virtual ~HttpHandler() { } virtual bool IsServedUri(const UriComponents& uri) = 0; virtual void Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& getArguments, const std::string& postData) = 0; static void ParseGetQuery(HttpHandler::Arguments& result, const char* query); static std::string GetArgument(const Arguments& getArguments, const std::string& name, const std::string& defaultValue); static void ParseCookies(HttpHandler::Arguments& result, const HttpHandler::Arguments& httpHeaders); }; } Orthanc-0.7.2/Core/HttpServer/HttpOutput.cpp0000644000000000000000000001420312237177136017117 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpOutput.h" #include #include #include #include #include "../OrthancException.h" #include "../Toolbox.h" namespace Orthanc { void HttpOutput::SendString(const std::string& s) { if (s.size() > 0) { Send(&s[0], s.size()); } } void HttpOutput::PrepareOkHeader(Header& header, const char* contentType, bool hasContentLength, uint64_t contentLength, const char* contentFilename) { header.clear(); if (contentType && contentType[0] != '\0') { header.push_back(std::make_pair("Content-Type", std::string(contentType))); } if (hasContentLength) { header.push_back(std::make_pair("Content-Length", boost::lexical_cast(contentLength))); } if (contentFilename && contentFilename[0] != '\0') { std::string attachment = "attachment; filename=\"" + std::string(contentFilename) + "\""; header.push_back(std::make_pair("Content-Disposition", attachment)); } } void HttpOutput::SendOkHeader(const char* contentType, bool hasContentLength, uint64_t contentLength, const char* contentFilename) { Header header; PrepareOkHeader(header, contentType, hasContentLength, contentLength, contentFilename); SendOkHeader(header); } void HttpOutput::SendOkHeader(const Header& header) { std::string s = "HTTP/1.1 200 OK\r\n"; for (Header::const_iterator it = header.begin(); it != header.end(); ++it) { s += it->first + ": " + it->second + "\r\n"; } s += "\r\n"; Send(&s[0], s.size()); } void HttpOutput::SendMethodNotAllowedError(const std::string& allowed) { std::string s = "HTTP/1.1 405 " + std::string(EnumerationToString(HttpStatus_405_MethodNotAllowed)) + "\r\nAllow: " + allowed + "\r\n\r\n"; Send(&s[0], s.size()); } void HttpOutput::SendHeader(HttpStatus status) { if (status == HttpStatus_200_Ok || status == HttpStatus_405_MethodNotAllowed) { throw OrthancException("Please use the dedicated methods to this HTTP status code in HttpOutput"); } SendHeaderInternal(status); } void HttpOutput::SendHeaderInternal(HttpStatus status) { std::string s = "HTTP/1.1 " + boost::lexical_cast(status) + " " + std::string(EnumerationToString(status)) + "\r\n\r\n"; Send(&s[0], s.size()); } void HttpOutput::AnswerBufferWithContentType(const std::string& buffer, const std::string& contentType) { SendOkHeader(contentType.c_str(), true, buffer.size(), NULL); SendString(buffer); } void HttpOutput::PrepareCookies(Header& header, const HttpHandler::Arguments& cookies) { for (HttpHandler::Arguments::const_iterator it = cookies.begin(); it != cookies.end(); ++it) { header.push_back(std::make_pair("Set-Cookie", it->first + "=" + it->second)); } } void HttpOutput::AnswerBufferWithContentType(const std::string& buffer, const std::string& contentType, const HttpHandler::Arguments& cookies) { Header header; PrepareOkHeader(header, contentType.c_str(), true, buffer.size(), NULL); PrepareCookies(header, cookies); SendOkHeader(header); SendString(buffer); } void HttpOutput::AnswerBufferWithContentType(const void* buffer, size_t size, const std::string& contentType) { SendOkHeader(contentType.c_str(), true, size, NULL); Send(buffer, size); } void HttpOutput::AnswerBufferWithContentType(const void* buffer, size_t size, const std::string& contentType, const HttpHandler::Arguments& cookies) { Header header; PrepareOkHeader(header, contentType.c_str(), true, size, NULL); PrepareCookies(header, cookies); SendOkHeader(header); Send(buffer, size); } void HttpOutput::Redirect(const std::string& path) { std::string s = "HTTP/1.1 301 " + std::string(EnumerationToString(HttpStatus_301_MovedPermanently)) + "\r\nLocation: " + path + "\r\n\r\n"; Send(&s[0], s.size()); } } Orthanc-0.7.2/Core/HttpServer/HttpOutput.h0000644000000000000000000000702612237177136016571 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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" #include "HttpHandler.h" namespace Orthanc { class HttpOutput { private: typedef std::list< std::pair > Header; void SendHeaderInternal(HttpStatus status); void PrepareOkHeader(Header& header, const char* contentType, bool hasContentLength, uint64_t contentLength, const char* contentFilename); void SendOkHeader(const Header& header); void PrepareCookies(Header& header, const HttpHandler::Arguments& cookies); public: virtual ~HttpOutput() { } virtual void Send(const void* buffer, size_t length) = 0; void SendOkHeader(const char* contentType, bool hasContentLength, uint64_t contentLength, const char* contentFilename); void SendString(const std::string& s); void SendMethodNotAllowedError(const std::string& allowed); void SendHeader(HttpStatus status); void Redirect(const std::string& path); // Higher-level constructs to send entire buffers ---------------------------- void AnswerBufferWithContentType(const std::string& buffer, const std::string& contentType); void AnswerBufferWithContentType(const std::string& buffer, const std::string& contentType, const HttpHandler::Arguments& cookies); void AnswerBufferWithContentType(const void* buffer, size_t size, const std::string& contentType); void AnswerBufferWithContentType(const void* buffer, size_t size, const std::string& contentType, const HttpHandler::Arguments& cookies); }; } Orthanc-0.7.2/Core/HttpServer/MongooseServer.cpp0000644000000000000000000005156312237177136017746 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "MongooseServer.h" #include #include #include #include #include #include #include #include #include #include "../OrthancException.h" #include "../ChunkedBuffer.h" #include "HttpOutput.h" #include "mongoose.h" #define ORTHANC_REALM "Orthanc Secure Area" static const long LOCALHOST = (127ll << 24) + 1ll; namespace Orthanc { static const char multipart[] = "multipart/form-data; boundary="; static unsigned int multipartLength = sizeof(multipart) / sizeof(char) - 1; namespace { // Anonymous namespace to avoid clashes between compilation modules class MongooseOutput : public HttpOutput { private: struct mg_connection* connection_; public: MongooseOutput(struct mg_connection* connection) : connection_(connection) { } virtual void Send(const void* buffer, size_t length) { if (length > 0) { mg_write(connection_, buffer, length); } } }; 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 { 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 MongooseServer::PImpl { struct mg_context *context_; ChunkStore chunkStore_; }; ChunkStore& MongooseServer::GetChunkStore() { return pimpl_->chunkStore_; } HttpHandler* MongooseServer::FindHandler(const UriComponents& forUri) const { for (Handlers::const_iterator it = handlers_.begin(); it != handlers_.end(); ++it) { if ((*it)->IsServedUri(forUri)) { return *it; } } return NULL; } static PostDataStatus ReadBody(std::string& postData, struct mg_connection *connection, const HttpHandler::Arguments& headers) { HttpHandler::Arguments::const_iterator cs = headers.find("content-length"); if (cs == headers.end()) { return PostDataStatus_NoLength; } int length; try { length = boost::lexical_cast(cs->second); } catch (boost::bad_lexical_cast) { return PostDataStatus_NoLength; } if (length < 0) { length = 0; } postData.resize(length); size_t pos = 0; while (length > 0) { int r = mg_read(connection, &postData[pos], length); if (r <= 0) { return PostDataStatus_Failure; } assert(r <= length); length -= r; pos += r; } return PostDataStatus_Success; } static PostDataStatus ParseMultipartPost(std::string &completedFile, struct mg_connection *connection, const HttpHandler::Arguments& headers, const std::string& contentType, ChunkStore& chunkStore) { std::string boundary = "--" + contentType.substr(multipartLength); std::string postData; PostDataStatus status = ReadBody(postData, connection, headers); if (status != PostDataStatus_Success) { return status; } /*for (HttpHandler::Arguments::const_iterator i = headers.begin(); i != headers.end(); i++) { std::cout << "Header [" << i->first << "] = " << i->second << "\n"; } printf("CHUNK\n");*/ typedef HttpHandler::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(); try { FindIterator last; for (FindIterator it = make_find_iterator(postData, 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 void SendUnauthorized(HttpOutput& output) { std::string s = "HTTP/1.1 401 Unauthorized\r\n" "WWW-Authenticate: Basic realm=\"" ORTHANC_REALM "\"" "\r\n\r\n"; output.Send(&s[0], s.size()); } static bool Authorize(const MongooseServer& that, const HttpHandler::Arguments& headers, HttpOutput& output) { bool granted = false; HttpHandler::Arguments::const_iterator auth = headers.find("authorization"); if (auth != headers.end()) { std::string s = auth->second; if (s.substr(0, 6) == "Basic ") { std::string b64 = s.substr(6); granted = that.IsValidBasicHttpAuthentication(b64); } } if (!granted) { SendUnauthorized(output); return false; } else { return true; } } static std::string GetAuthenticatedUsername(const HttpHandler::Arguments& headers) { HttpHandler::Arguments::const_iterator auth = headers.find("authorization"); if (auth == headers.end()) { return ""; } std::string s = auth->second; if (s.substr(0, 6) != "Basic ") { return ""; } std::string b64 = s.substr(6); std::string decoded = Toolbox::DecodeBase64(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 HttpHandler::Arguments& headers, const HttpHandler::Arguments& argumentsGET) { std::string overriden; // Check whether some PUT/DELETE faking is done // 1. Faking with Google's approach HttpHandler::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 methodOverride = argumentsGET.find("_method"); if (methodOverride != argumentsGET.end()) { overriden = methodOverride->second; } } 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* Callback(enum mg_event event, struct mg_connection *connection, const struct mg_request_info *request) { if (event == MG_NEW_REQUEST) { MongooseServer* that = reinterpret_cast(request->user_data); MongooseOutput output(connection); // Check remote calls if (!that->IsRemoteAccessAllowed() && request->remote_ip != LOCALHOST) { SendUnauthorized(output); return (void*) ""; } // Extract the HTTP headers HttpHandler::Arguments headers; for (int i = 0; i < request->num_headers; i++) { std::string name = request->http_headers[i].name; std::transform(name.begin(), name.end(), name.begin(), ::tolower); headers.insert(std::make_pair(name, request->http_headers[i].value)); } // Extract the GET arguments HttpHandler::Arguments argumentsGET; if (!strcmp(request->request_method, "GET")) { HttpHandler::ParseGetQuery(argumentsGET, request->query_string); } // Compute the HTTP method, taking method faking into consideration HttpMethod method; if (!ExtractMethod(method, request, headers, argumentsGET)) { output.SendHeader(HttpStatus_400_BadRequest); return (void*) ""; } // Authenticate this connection if (that->IsAuthenticationEnabled() && !Authorize(*that, headers, output)) { return (void*) ""; } // Apply the filter, if it is installed const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter(); if (filter != NULL) { std::string username = GetAuthenticatedUsername(headers); 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]); if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str())) { SendUnauthorized(output); return (void*) ""; } } // Extract the body of the request for PUT and POST std::string body; if (method == HttpMethod_Post || method == HttpMethod_Put) { PostDataStatus status; HttpHandler::Arguments::const_iterator ct = headers.find("content-type"); if (ct == headers.end()) { // No content-type specified. Assume no multi-part content occurs at this point. status = ReadBody(body, connection, headers); } else { std::string contentType = ct->second; if (contentType.size() >= multipartLength && !memcmp(contentType.c_str(), multipart, multipartLength)) { status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore()); } else { status = ReadBody(body, connection, headers); } } switch (status) { case PostDataStatus_NoLength: output.SendHeader(HttpStatus_411_LengthRequired); return (void*) ""; case PostDataStatus_Failure: output.SendHeader(HttpStatus_400_BadRequest); return (void*) ""; case PostDataStatus_Pending: output.AnswerBufferWithContentType(NULL, 0, ""); return (void*) ""; default: break; } } // Call the proper handler for this URI UriComponents uri; try { Toolbox::SplitUriComponents(uri, request->uri); } catch (OrthancException) { output.SendHeader(HttpStatus_400_BadRequest); return (void*) ""; } HttpHandler* handler = that->FindHandler(uri); if (handler) { try { LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); handler->Handle(output, method, uri, headers, argumentsGET, body); } catch (OrthancException& e) { LOG(ERROR) << "MongooseServer Exception [" << e.What() << "]"; output.SendHeader(HttpStatus_500_InternalServerError); } catch (boost::bad_lexical_cast&) { LOG(ERROR) << "MongooseServer Exception: Bad lexical cast"; output.SendHeader(HttpStatus_400_BadRequest); } catch (std::runtime_error&) { LOG(ERROR) << "MongooseServer Exception: Presumably a bad JSON request"; output.SendHeader(HttpStatus_400_BadRequest); } } else { output.SendHeader(HttpStatus_404_NotFound); } // Mark as processed return (void*) ""; } else { return NULL; } } bool MongooseServer::IsRunning() const { return (pimpl_->context_ != NULL); } MongooseServer::MongooseServer() : pimpl_(new PImpl) { pimpl_->context_ = NULL; remoteAllowed_ = false; authentication_ = false; ssl_ = false; port_ = 8000; filter_ = NULL; } MongooseServer::~MongooseServer() { Stop(); ClearHandlers(); } void MongooseServer::SetPortNumber(uint16_t port) { Stop(); port_ = port; } void MongooseServer::Start() { if (!IsRunning()) { std::string port = boost::lexical_cast(port_); if (ssl_) { port += "s"; } const char *options[] = { "listening_ports", port.c_str(), ssl_ ? "ssl_certificate" : NULL, certificate_.c_str(), NULL }; pimpl_->context_ = mg_start(&Callback, this, options); if (!pimpl_->context_) { throw OrthancException("Unable to launch the Mongoose server"); } } } void MongooseServer::Stop() { if (IsRunning()) { mg_stop(pimpl_->context_); pimpl_->context_ = NULL; } } void MongooseServer::RegisterHandler(HttpHandler* handler) { Stop(); handlers_.push_back(handler); } void MongooseServer::ClearHandlers() { Stop(); for (Handlers::iterator it = handlers_.begin(); it != handlers_.end(); ++it) { delete *it; } } void MongooseServer::ClearUsers() { Stop(); registeredUsers_.clear(); } void MongooseServer::RegisterUser(const char* username, const char* password) { Stop(); std::string tag = std::string(username) + ":" + std::string(password); registeredUsers_.insert(Toolbox::EncodeBase64(tag)); } void MongooseServer::SetSslEnabled(bool enabled) { Stop(); #if ORTHANC_SSL_ENABLED == 0 if (enabled) { throw OrthancException("Orthanc has been built without SSL support"); } else { ssl_ = false; } #else ssl_ = enabled; #endif } void MongooseServer::SetAuthenticationEnabled(bool enabled) { Stop(); authentication_ = enabled; } void MongooseServer::SetSslCertificate(const char* path) { Stop(); certificate_ = path; } void MongooseServer::SetRemoteAccessAllowed(bool allowed) { Stop(); remoteAllowed_ = allowed; } void MongooseServer::SetIncomingHttpRequestFilter(IIncomingHttpRequestFilter& filter) { Stop(); filter_ = &filter; } bool MongooseServer::IsValidBasicHttpAuthentication(const std::string& basic) const { return registeredUsers_.find(basic) != registeredUsers_.end(); } } Orthanc-0.7.2/Core/HttpServer/MongooseServer.h0000644000000000000000000000752112237177136017406 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "HttpHandler.h" #include #include #include #include #include namespace Orthanc { class ChunkStore; class IIncomingHttpRequestFilter { public: virtual ~IIncomingHttpRequestFilter() { } virtual bool IsAllowed(HttpMethod method, const char* uri, const char* ip, const char* username) const = 0; }; class MongooseServer { private: // http://stackoverflow.com/questions/311166/stdauto-ptr-or-boostshared-ptr-for-pimpl-idiom struct PImpl; boost::shared_ptr pimpl_; typedef std::list Handlers; Handlers handlers_; typedef std::set RegisteredUsers; RegisteredUsers registeredUsers_; bool remoteAllowed_; bool authentication_; bool ssl_; std::string certificate_; uint16_t port_; IIncomingHttpRequestFilter* filter_; bool IsRunning() const; public: MongooseServer(); ~MongooseServer(); 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); void RegisterHandler(HttpHandler* handler); // This takes the ownership bool IsAuthenticationEnabled() const { return authentication_; } void SetAuthenticationEnabled(bool enabled); bool IsSslEnabled() const { return ssl_; } void SetSslEnabled(bool enabled); const std::string& GetSslCertificate() const { return certificate_; } void SetSslCertificate(const char* path); bool IsRemoteAccessAllowed() const { return remoteAllowed_; } void SetRemoteAccessAllowed(bool allowed); const IIncomingHttpRequestFilter* GetIncomingHttpRequestFilter() const { return filter_; } void SetIncomingHttpRequestFilter(IIncomingHttpRequestFilter& filter); void ClearHandlers(); // Can return NULL if no handler is associated to this URI HttpHandler* FindHandler(const UriComponents& forUri) const; ChunkStore& GetChunkStore(); bool IsValidBasicHttpAuthentication(const std::string& basic) const; }; } Orthanc-0.7.2/Core/ICommand.h0000644000000000000000000000345412237177136014013 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 { /** * This class is the base class for the "Command" design pattern. * http://en.wikipedia.org/wiki/Command_pattern **/ class ICommand : public IDynamicObject { public: virtual bool Execute() = 0; }; } Orthanc-0.7.2/Core/IDynamicObject.h0000644000000000000000000000366612237177136015155 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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() { } }; } Orthanc-0.7.2/Core/Lua/LuaContext.cpp0000644000000000000000000001011312237177136015454 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "LuaContext.h" #include extern "C" { #include #include } namespace Orthanc { int LuaContext::PrintToLog(lua_State *state) { // Get the pointer to the "LuaContext" underlying object lua_getglobal(state, "_LuaContext"); assert(lua_type(state, -1) == LUA_TLIGHTUSERDATA); LuaContext* that = const_cast(reinterpret_cast(lua_topointer(state, -1))); assert(that != NULL); lua_pop(state, 1); // 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(INFO) << "Lua says: " << result; that->log_.append(result); that->log_.append("\n"); return 0; } LuaContext::LuaContext() { lua_ = luaL_newstate(); if (!lua_) { throw LuaException("Unable to create the Lua context"); } luaL_openlibs(lua_); lua_register(lua_, "print", PrintToLog); lua_pushlightuserdata(lua_, this); lua_setglobal(lua_, "_LuaContext"); } LuaContext::~LuaContext() { lua_close(lua_); } void LuaContext::Execute(std::string* output, const std::string& command) { boost::mutex::scoped_lock lock(mutex_); 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 LuaException(description); } if (output != NULL) { *output = log_; } } void LuaContext::Execute(EmbeddedResources::FileResourceId resource) { std::string command; EmbeddedResources::GetFileResource(command, resource); Execute(command); } bool LuaContext::IsExistingFunction(const char* name) { boost::mutex::scoped_lock lock(mutex_); lua_settop(lua_, 0); lua_getglobal(lua_, name); return lua_type(lua_, -1) == LUA_TFUNCTION; } } Orthanc-0.7.2/Core/Lua/LuaContext.h0000644000000000000000000000451512237177136015132 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "LuaException.h" #include extern "C" { #include } #include namespace Orthanc { class LuaContext : public boost::noncopyable { private: friend class LuaFunctionCall; lua_State *lua_; boost::mutex mutex_; std::string log_; static int PrintToLog(lua_State *L); void Execute(std::string* output, const std::string& command); public: LuaContext(); ~LuaContext(); void Execute(const std::string& command) { Execute(NULL, command); } void Execute(std::string& output, const std::string& command) { Execute(&output, command); } void Execute(EmbeddedResources::FileResourceId resource); bool IsExistingFunction(const char* name); }; } Orthanc-0.7.2/Core/Lua/LuaException.h0000644000000000000000000000352612237177136015445 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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" namespace Orthanc { class LuaException : public OrthancException { public: LuaException(const char* explanation) : OrthancException(explanation) { } LuaException(const std::string& explanation) : OrthancException(explanation) { } }; } Orthanc-0.7.2/Core/Lua/LuaFunctionCall.cpp0000644000000000000000000001246112237177136016421 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "LuaFunctionCall.h" namespace Orthanc { void LuaFunctionCall::CheckAlreadyExecuted() { if (isExecuted_) { throw LuaException("Arguments cannot be pushed after the function is executed"); } } LuaFunctionCall::LuaFunctionCall(LuaContext& context, const char* functionName) : context_(context), lock_(context.mutex_), 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_pushstring(context_.lua_, value.c_str()); } 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(); if (value.isString()) { lua_pushstring(context_.lua_, value.asCString()); } else if (value.isDouble()) { lua_pushnumber(context_.lua_, value.asDouble()); } else if (value.isInt()) { lua_pushinteger(context_.lua_, value.asInt()); } else if (value.isUInt()) { lua_pushinteger(context_.lua_, value.asUInt()); } else if (value.isBool()) { lua_pushboolean(context_.lua_, value.asBool()); } else if (value.isNull()) { lua_pushnil(context_.lua_); } else if (value.isArray()) { lua_newtable(context_.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(context_.lua_, i + 1); // Push the value of the cell PushJSON(value[i]); // Stores the pair in the table lua_rawset(context_.lua_, -3); } } else if (value.isObject()) { lua_newtable(context_.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_pushstring(context_.lua_, it->c_str()); // Push the value of the cell PushJSON(value[*it]); // Stores the pair in the table lua_rawset(context_.lua_, -3); } } else { throw LuaException("Unsupported JSON conversion"); } } void LuaFunctionCall::Execute(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 LuaException(description); } if (lua_gettop(context_.lua_) < numOutputs) { throw LuaException("The function does not give the expected number of outputs"); } isExecuted_ = true; } bool LuaFunctionCall::ExecutePredicate() { Execute(1); if (lua_gettop(context_.lua_) == 0) { throw LuaException("No output was provided by the function"); } if (!lua_isboolean(context_.lua_, 1)) { throw LuaException("The function is not a predicate (only true/false outputs allowed)"); } return lua_toboolean(context_.lua_, 1) != 0; } } Orthanc-0.7.2/Core/Lua/LuaFunctionCall.h0000644000000000000000000000422012237177136016060 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 namespace Orthanc { class LuaFunctionCall : public boost::noncopyable { private: LuaContext& context_; boost::mutex::scoped_lock lock_; bool isExecuted_; void CheckAlreadyExecuted(); 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 Execute(int numOutputs = 0); bool ExecutePredicate(); }; } Orthanc-0.7.2/Core/MultiThreading/ArrayFilledByThreads.cpp0000644000000000000000000000410712237177136021577 0ustar 00000000000000#include "ArrayFilledByThreads.h" #include "../MultiThreading/ThreadedCommandProcessor.h" #include "../OrthancException.h" namespace Orthanc { class ArrayFilledByThreads::Command : public ICommand { private: ArrayFilledByThreads& that_; size_t index_; public: Command(ArrayFilledByThreads& that, size_t index) : that_(that), index_(index) { } virtual bool Execute() { std::auto_ptr obj(that_.filler_.GetFillerItem(index_)); if (obj.get() == NULL) { return false; } else { boost::mutex::scoped_lock lock(that_.mutex_); that_.array_[index_] = obj.release(); return true; } } }; void ArrayFilledByThreads::Clear() { for (size_t i = 0; i < array_.size(); i++) { if (array_[i]) delete array_[i]; } array_.clear(); filled_ = false; } void ArrayFilledByThreads::Update() { if (!filled_) { array_.resize(filler_.GetFillerSize()); Orthanc::ThreadedCommandProcessor processor(threadCount_); for (size_t i = 0; i < array_.size(); i++) { processor.Post(new Command(*this, i)); } processor.Join(); filled_ = true; } } ArrayFilledByThreads::ArrayFilledByThreads(IFiller& filler) : filler_(filler) { filled_ = false; threadCount_ = 4; } ArrayFilledByThreads::~ArrayFilledByThreads() { Clear(); } void ArrayFilledByThreads::Reload() { Clear(); Update(); } void ArrayFilledByThreads::Invalidate() { Clear(); } void ArrayFilledByThreads::SetThreadCount(unsigned int t) { if (t < 1) { throw OrthancException(ErrorCode_ParameterOutOfRange); } threadCount_ = t; } size_t ArrayFilledByThreads::GetSize() { Update(); return array_.size(); } IDynamicObject& ArrayFilledByThreads::GetItem(size_t index) { if (index >= GetSize()) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } return *array_[index]; } } Orthanc-0.7.2/Core/MultiThreading/ArrayFilledByThreads.h0000644000000000000000000000146212237177136021245 0ustar 00000000000000#pragma once #include #include "../ICommand.h" namespace Orthanc { class ArrayFilledByThreads { public: class IFiller { public: virtual size_t GetFillerSize() = 0; virtual IDynamicObject* GetFillerItem(size_t index) = 0; }; private: IFiller& filler_; boost::mutex mutex_; std::vector array_; bool filled_; unsigned int threadCount_; class Command; void Clear(); void Update(); public: ArrayFilledByThreads(IFiller& filler); ~ArrayFilledByThreads(); void Reload(); void Invalidate(); void SetThreadCount(unsigned int t); unsigned int GetThreadCount() const { return threadCount_; } size_t GetSize(); IDynamicObject& GetItem(size_t index); }; } Orthanc-0.7.2/Core/MultiThreading/BagOfRunnablesBySteps.cpp0000644000000000000000000001201312237177136021730 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "BagOfRunnablesBySteps.h" #include #include namespace Orthanc { struct BagOfRunnablesBySteps::PImpl { bool continue_; bool stopFinishListener_; boost::mutex mutex_; boost::condition_variable oneThreadIsStopped_; boost::condition_variable oneThreadIsJoined_; // The list of threads that are waiting to be joined. typedef std::stack StoppedThreads; StoppedThreads stoppedThreads_; // The set of active runnables, i.e. the runnables that have not // finished their job yet, plus the runnables that have not been // joined yet. typedef std::map ActiveThreads; ActiveThreads activeThreads_; // The thread that joins the runnables after they stop std::auto_ptr finishListener_; }; void BagOfRunnablesBySteps::RunnableThread(BagOfRunnablesBySteps* bag, IRunnableBySteps* runnable) { while (bag->pimpl_->continue_) { if (!runnable->Step()) { break; } } { // Register this runnable as having stopped boost::mutex::scoped_lock lock(bag->pimpl_->mutex_); bag->pimpl_->stoppedThreads_.push(runnable); bag->pimpl_->oneThreadIsStopped_.notify_one(); } } void BagOfRunnablesBySteps::FinishListener(BagOfRunnablesBySteps* bag) { boost::mutex::scoped_lock lock(bag->pimpl_->mutex_); while (!bag->pimpl_->stopFinishListener_) { while (!bag->pimpl_->stoppedThreads_.empty()) { std::auto_ptr r(bag->pimpl_->stoppedThreads_.top()); bag->pimpl_->stoppedThreads_.pop(); assert(r.get() != NULL); assert(bag->pimpl_->activeThreads_.find(r.get()) != bag->pimpl_->activeThreads_.end()); std::auto_ptr t(bag->pimpl_->activeThreads_[r.get()]); bag->pimpl_->activeThreads_.erase(r.get()); assert(t.get() != NULL); assert(bag->pimpl_->activeThreads_.find(r.get()) == bag->pimpl_->activeThreads_.end()); if (t->joinable()) { t->join(); } bag->pimpl_->oneThreadIsJoined_.notify_one(); } bag->pimpl_->oneThreadIsStopped_.wait(lock); } } BagOfRunnablesBySteps::BagOfRunnablesBySteps() : pimpl_(new PImpl) { pimpl_->continue_ = true; pimpl_->stopFinishListener_ = false; // Everyting is set up, the finish listener can be started pimpl_->finishListener_.reset(new boost::thread(FinishListener, this)); } BagOfRunnablesBySteps::~BagOfRunnablesBySteps() { StopAll(); // Stop the finish listener pimpl_->stopFinishListener_ = true; pimpl_->oneThreadIsStopped_.notify_one(); // Awakens the listener if (pimpl_->finishListener_->joinable()) { pimpl_->finishListener_->join(); } } void BagOfRunnablesBySteps::Add(IRunnableBySteps* runnable) { // Make sure the runnable is deleted is something goes wrong std::auto_ptr runnableRabi(runnable); boost::mutex::scoped_lock lock(pimpl_->mutex_); boost::thread* t(new boost::thread(RunnableThread, this, runnable)); pimpl_->activeThreads_.insert(std::make_pair(runnableRabi.release(), t)); } void BagOfRunnablesBySteps::StopAll() { boost::mutex::scoped_lock lock(pimpl_->mutex_); pimpl_->continue_ = false; while (pimpl_->activeThreads_.size() > 0) { pimpl_->oneThreadIsJoined_.wait(lock); } pimpl_->continue_ = true; } } Orthanc-0.7.2/Core/MultiThreading/BagOfRunnablesBySteps.h0000644000000000000000000000412212237177136021377 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 #include namespace Orthanc { class BagOfRunnablesBySteps : public boost::noncopyable { private: struct PImpl; boost::shared_ptr pimpl_; static void RunnableThread(BagOfRunnablesBySteps* bag, IRunnableBySteps* runnable); static void FinishListener(BagOfRunnablesBySteps* bag); public: BagOfRunnablesBySteps(); ~BagOfRunnablesBySteps(); void Add(IRunnableBySteps* runnable); void StopAll(); }; } Orthanc-0.7.2/Core/MultiThreading/IRunnableBySteps.h0000644000000000000000000000361612237177136020435 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 namespace Orthanc { class IRunnableBySteps { 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()); } }; } Orthanc-0.7.2/Core/MultiThreading/SharedMessageQueue.cpp0000644000000000000000000000645512237177136021323 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "SharedMessageQueue.h" namespace Orthanc { SharedMessageQueue::SharedMessageQueue(unsigned int maxSize) { 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_) { // Too many elements in the queue: First remove the oldest delete queue_.front(); queue_.pop_front(); } queue_.push_back(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::auto_ptr message(queue_.front()); queue_.pop_front(); 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 if (!queue_.empty()) { if (millisecondsTimeout == 0) { emptied_.wait(lock); } else { if (!emptied_.timed_wait (lock, boost::posix_time::milliseconds(millisecondsTimeout))) { return false; } } } return true; } } Orthanc-0.7.2/Core/MultiThreading/SharedMessageQueue.h0000644000000000000000000000436412237177136020765 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 { private: typedef std::list Queue; unsigned int maxSize_; Queue queue_; boost::mutex mutex_; boost::condition_variable elementAvailable_; boost::condition_variable emptied_; public: 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); }; } Orthanc-0.7.2/Core/MultiThreading/ThreadedCommandProcessor.cpp0000644000000000000000000001222412237177136022511 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "ThreadedCommandProcessor.h" #include "../OrthancException.h" namespace Orthanc { static const int32_t TIMEOUT = 10; void ThreadedCommandProcessor::Processor(ThreadedCommandProcessor* that) { while (!that->done_) { std::auto_ptr command(that->queue_.Dequeue(TIMEOUT)); if (command.get() != NULL) { bool success = false; try { if (that->success_) { // No command has failed so far if (that->cancel_) { // The commands have been canceled. Skip the execution // of this command, yet mark it as succeeded. success = true; } else { success = dynamic_cast(*command).Execute(); } } else { // A command has already failed. Skip the execution of this command. } } catch (OrthancException) { } { boost::mutex::scoped_lock lock(that->mutex_); assert(that->remainingCommands_ > 0); that->remainingCommands_--; if (!success) { if (!that->cancel_ && that->listener_ && that->success_) { // This is the first command that fails that->listener_->SignalFailure(); } that->success_ = false; } else { if (!that->cancel_ && that->listener_) { if (that->remainingCommands_ == 0) { that->listener_->SignalSuccess(that->totalCommands_); } else { that->listener_->SignalProgress(that->totalCommands_ - that->remainingCommands_, that->totalCommands_); } } } that->processedCommand_.notify_all(); } } } } ThreadedCommandProcessor::ThreadedCommandProcessor(unsigned int numThreads) { if (numThreads < 1) { throw OrthancException(ErrorCode_ParameterOutOfRange); } listener_ = NULL; success_ = true; done_ = false; cancel_ = false; threads_.resize(numThreads); remainingCommands_ = 0; totalCommands_ = 0; for (unsigned int i = 0; i < numThreads; i++) { threads_[i] = new boost::thread(Processor, this); } } ThreadedCommandProcessor::~ThreadedCommandProcessor() { done_ = true; for (unsigned int i = 0; i < threads_.size(); i++) { boost::thread* t = threads_[i]; if (t != NULL) { if (t->joinable()) { t->join(); } delete t; } } } void ThreadedCommandProcessor::Post(ICommand* command) { boost::mutex::scoped_lock lock(mutex_); queue_.Enqueue(command); remainingCommands_++; totalCommands_++; } bool ThreadedCommandProcessor::Join() { boost::mutex::scoped_lock lock(mutex_); while (!remainingCommands_ == 0) { processedCommand_.wait(lock); } if (cancel_ && listener_) { listener_->SignalCancel(); } // Reset the sequence counters for subsequent commands bool hasSucceeded = success_; success_ = true; totalCommands_ = 0; cancel_ = false; return hasSucceeded; } void ThreadedCommandProcessor::Cancel() { boost::mutex::scoped_lock lock(mutex_); cancel_ = true; } void ThreadedCommandProcessor::SetListener(IListener& listener) { boost::mutex::scoped_lock lock(mutex_); listener_ = &listener; } } Orthanc-0.7.2/Core/MultiThreading/ThreadedCommandProcessor.h0000644000000000000000000000525212237177136022161 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../ICommand.h" #include "SharedMessageQueue.h" namespace Orthanc { class ThreadedCommandProcessor { public: class IListener { public: virtual ~IListener() { } virtual void SignalProgress(unsigned int current, unsigned int total) = 0; virtual void SignalSuccess(unsigned int total) = 0; virtual void SignalFailure() = 0; virtual void SignalCancel() = 0; }; private: SharedMessageQueue queue_; bool done_; bool cancel_; std::vector threads_; IListener* listener_; boost::mutex mutex_; bool success_; unsigned int remainingCommands_, totalCommands_; boost::condition_variable processedCommand_; static void Processor(ThreadedCommandProcessor* that); public: ThreadedCommandProcessor(unsigned int numThreads); ~ThreadedCommandProcessor(); // This takes the ownership of the command void Post(ICommand* command); bool Join(); void Cancel(); void SetListener(IListener& listener); IListener& GetListener() const { return *listener_; } }; } Orthanc-0.7.2/Core/OrthancException.cpp0000644000000000000000000000640312237177136016131 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "OrthancException.h" namespace Orthanc { const char* OrthancException::What() const { if (error_ == ErrorCode_Custom) { return custom_.c_str(); } else { return GetDescription(error_); } } const char* OrthancException::GetDescription(ErrorCode error) { switch (error) { case ErrorCode_Success: return "Success"; case ErrorCode_ParameterOutOfRange: return "Parameter out of range"; case ErrorCode_NotImplemented: return "Not implemented yet"; case ErrorCode_InternalError: return "Internal error"; case ErrorCode_NotEnoughMemory: return "Not enough memory"; case ErrorCode_UriSyntax: return "Badly formatted URI"; case ErrorCode_BadParameterType: return "Bad type for a parameter"; case ErrorCode_InexistentFile: return "Inexistent file"; case ErrorCode_BadFileFormat: return "Bad file format"; case ErrorCode_CannotWriteFile: return "Cannot write to file"; case ErrorCode_Timeout: return "Timeout"; case ErrorCode_UnknownResource: return "Unknown resource"; case ErrorCode_BadSequenceOfCalls: return "Bad sequence of calls"; case ErrorCode_IncompatibleDatabaseVersion: return "Incompatible version of the database"; case ErrorCode_FullStorage: return "The file storage is full"; 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_Custom: default: return "???"; } } } Orthanc-0.7.2/Core/OrthancException.h0000644000000000000000000000421212237177136015572 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Enumerations.h" namespace Orthanc { class OrthancException { protected: ErrorCode error_; std::string custom_; public: static const char* GetDescription(ErrorCode error); OrthancException(const char* custom) : error_(ErrorCode_Custom), custom_(custom) { } OrthancException(const std::string& custom) : error_(ErrorCode_Custom), custom_(custom) { } OrthancException(ErrorCode error) : error_(error) { } ErrorCode GetErrorCode() const { return error_; } const char* What() const; }; } Orthanc-0.7.2/Core/RestApi/RestApi.cpp0000644000000000000000000001732112237177136015573 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "RestApi.h" #include // To define "_exit()" under Windows #include namespace Orthanc { bool RestApi::Call::ParseJsonRequestInternal(Json::Value& result, const char* request) { result.clear(); Json::Reader reader; return reader.parse(request, result); } bool RestApi::GetCall::ParseJsonRequest(Json::Value& result) const { result.clear(); for (HttpHandler::Arguments::const_iterator it = getArguments_.begin(); it != getArguments_.end(); ++it) { result[it->first] = it->second; } return true; } bool RestApi::IsGetAccepted(const UriComponents& uri) { for (GetHandlers::const_iterator it = getHandlers_.begin(); it != getHandlers_.end(); ++it) { if (it->first->Match(uri)) { return true; } } return false; } bool RestApi::IsPutAccepted(const UriComponents& uri) { for (PutHandlers::const_iterator it = putHandlers_.begin(); it != putHandlers_.end(); ++it) { if (it->first->Match(uri)) { return true; } } return false; } bool RestApi::IsPostAccepted(const UriComponents& uri) { for (PostHandlers::const_iterator it = postHandlers_.begin(); it != postHandlers_.end(); ++it) { if (it->first->Match(uri)) { return true; } } return false; } bool RestApi::IsDeleteAccepted(const UriComponents& uri) { for (DeleteHandlers::const_iterator it = deleteHandlers_.begin(); it != deleteHandlers_.end(); ++it) { if (it->first->Match(uri)) { return true; } } return false; } static void AddMethod(std::string& target, const std::string& method) { if (target.size() > 0) target += "," + method; else target = method; } std::string RestApi::GetAcceptedMethods(const UriComponents& uri) { std::string s; if (IsGetAccepted(uri)) AddMethod(s, "GET"); if (IsPutAccepted(uri)) AddMethod(s, "PUT"); if (IsPostAccepted(uri)) AddMethod(s, "POST"); if (IsDeleteAccepted(uri)) AddMethod(s, "DELETE"); return s; } RestApi::~RestApi() { for (GetHandlers::iterator it = getHandlers_.begin(); it != getHandlers_.end(); ++it) { delete it->first; } for (PutHandlers::iterator it = putHandlers_.begin(); it != putHandlers_.end(); ++it) { delete it->first; } for (PostHandlers::iterator it = postHandlers_.begin(); it != postHandlers_.end(); ++it) { delete it->first; } for (DeleteHandlers::iterator it = deleteHandlers_.begin(); it != deleteHandlers_.end(); ++it) { delete it->first; } } bool RestApi::IsServedUri(const UriComponents& uri) { return (IsGetAccepted(uri) || IsPutAccepted(uri) || IsPostAccepted(uri) || IsDeleteAccepted(uri)); } void RestApi::Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& getArguments, const std::string& postData) { bool ok = false; RestApiOutput restOutput(output); RestApiPath::Components components; UriComponents trailing; if (method == HttpMethod_Get) { for (GetHandlers::const_iterator it = getHandlers_.begin(); it != getHandlers_.end(); ++it) { if (it->first->Match(components, trailing, uri)) { //LOG(INFO) << "REST GET call on: " << Toolbox::FlattenUri(uri); ok = true; GetCall call(restOutput, *this, headers, components, trailing, uri, getArguments); it->second(call); } } } else if (method == HttpMethod_Put) { for (PutHandlers::const_iterator it = putHandlers_.begin(); it != putHandlers_.end(); ++it) { if (it->first->Match(components, trailing, uri)) { //LOG(INFO) << "REST PUT call on: " << Toolbox::FlattenUri(uri); ok = true; PutCall call(restOutput, *this, headers, components, trailing, uri, postData); it->second(call); } } } else if (method == HttpMethod_Post) { for (PostHandlers::const_iterator it = postHandlers_.begin(); it != postHandlers_.end(); ++it) { if (it->first->Match(components, trailing, uri)) { //LOG(INFO) << "REST POST call on: " << Toolbox::FlattenUri(uri); ok = true; PostCall call(restOutput, *this, headers, components, trailing, uri, postData); it->second(call); } } } else if (method == HttpMethod_Delete) { for (DeleteHandlers::const_iterator it = deleteHandlers_.begin(); it != deleteHandlers_.end(); ++it) { if (it->first->Match(components, trailing, uri)) { //LOG(INFO) << "REST DELETE call on: " << Toolbox::FlattenUri(uri); ok = true; DeleteCall call(restOutput, *this, headers, components, trailing, uri); it->second(call); } } } if (!ok) { LOG(INFO) << "REST method " << EnumerationToString(method) << " not allowed on: " << Toolbox::FlattenUri(uri); output.SendMethodNotAllowedError(GetAcceptedMethods(uri)); } } void RestApi::Register(const std::string& path, GetHandler handler) { getHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } void RestApi::Register(const std::string& path, PutHandler handler) { putHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } void RestApi::Register(const std::string& path, PostHandler handler) { postHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } void RestApi::Register(const std::string& path, DeleteHandler handler) { deleteHandlers_.push_back(std::make_pair(new RestApiPath(path), handler)); } } Orthanc-0.7.2/Core/RestApi/RestApi.h0000644000000000000000000002073012237177136015236 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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/HttpHandler.h" #include "RestApiPath.h" #include "RestApiOutput.h" #include namespace Orthanc { class RestApi : public HttpHandler { public: class Call { friend class RestApi; private: RestApiOutput& output_; RestApi& context_; const HttpHandler::Arguments& httpHeaders_; const RestApiPath::Components& uriComponents_; const UriComponents& trailing_; const UriComponents& fullUri_; Call(RestApiOutput& output, RestApi& context, const HttpHandler::Arguments& httpHeaders, const RestApiPath::Components& uriComponents, const UriComponents& trailing, const UriComponents& fullUri) : output_(output), context_(context), httpHeaders_(httpHeaders), uriComponents_(uriComponents), trailing_(trailing), fullUri_(fullUri) { } protected: static bool ParseJsonRequestInternal(Json::Value& result, const char* request); public: 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 HttpHandler::GetArgument(uriComponents_, name, defaultValue); } std::string GetHttpHeader(const std::string& name, const std::string& defaultValue) const { return HttpHandler::GetArgument(httpHeaders_, name, defaultValue); } const HttpHandler::Arguments& GetHttpHeaders() const { return httpHeaders_; } void ParseCookies(HttpHandler::Arguments& result) const { HttpHandler::ParseCookies(result, httpHeaders_); } virtual bool ParseJsonRequest(Json::Value& result) const = 0; }; class GetCall : public Call { friend class RestApi; private: const HttpHandler::Arguments& getArguments_; public: GetCall(RestApiOutput& output, RestApi& context, const HttpHandler::Arguments& httpHeaders, const RestApiPath::Components& uriComponents, const UriComponents& trailing, const UriComponents& fullUri, const HttpHandler::Arguments& getArguments) : Call(output, context, httpHeaders, uriComponents, trailing, fullUri), getArguments_(getArguments) { } std::string GetArgument(const std::string& name, const std::string& defaultValue) const { return HttpHandler::GetArgument(getArguments_, name, defaultValue); } bool HasArgument(const std::string& name) const { return getArguments_.find(name) != getArguments_.end(); } virtual bool ParseJsonRequest(Json::Value& result) const; }; class PutCall : public Call { friend class RestApi; private: const std::string& data_; public: PutCall(RestApiOutput& output, RestApi& context, const HttpHandler::Arguments& httpHeaders, const RestApiPath::Components& uriComponents, const UriComponents& trailing, const UriComponents& fullUri, const std::string& data) : Call(output, context, httpHeaders, uriComponents, trailing, fullUri), data_(data) { } const std::string& GetPutBody() const { return data_; } virtual bool ParseJsonRequest(Json::Value& result) const { return ParseJsonRequestInternal(result, GetPutBody().c_str()); } }; class PostCall : public Call { friend class RestApi; private: const std::string& data_; public: PostCall(RestApiOutput& output, RestApi& context, const HttpHandler::Arguments& httpHeaders, const RestApiPath::Components& uriComponents, const UriComponents& trailing, const UriComponents& fullUri, const std::string& data) : Call(output, context, httpHeaders, uriComponents, trailing, fullUri), data_(data) { } const std::string& GetPostBody() const { return data_; } virtual bool ParseJsonRequest(Json::Value& result) const { return ParseJsonRequestInternal(result, GetPostBody().c_str()); } }; class DeleteCall : public Call { public: DeleteCall(RestApiOutput& output, RestApi& context, const HttpHandler::Arguments& httpHeaders, const RestApiPath::Components& uriComponents, const UriComponents& trailing, const UriComponents& fullUri) : Call(output, context, httpHeaders, uriComponents, trailing, fullUri) { } virtual bool ParseJsonRequest(Json::Value& result) const { result.clear(); return true; } }; typedef void (*GetHandler) (GetCall& call); typedef void (*DeleteHandler) (DeleteCall& call); typedef void (*PutHandler) (PutCall& call); typedef void (*PostHandler) (PostCall& call); private: typedef std::list< std::pair > GetHandlers; typedef std::list< std::pair > PutHandlers; typedef std::list< std::pair > PostHandlers; typedef std::list< std::pair > DeleteHandlers; GetHandlers getHandlers_; PutHandlers putHandlers_; PostHandlers postHandlers_; DeleteHandlers deleteHandlers_; bool IsGetAccepted(const UriComponents& uri); bool IsPutAccepted(const UriComponents& uri); bool IsPostAccepted(const UriComponents& uri); bool IsDeleteAccepted(const UriComponents& uri); std::string GetAcceptedMethods(const UriComponents& uri); public: RestApi() { } ~RestApi(); virtual bool IsServedUri(const UriComponents& uri); virtual void Handle(HttpOutput& output, HttpMethod method, const UriComponents& uri, const Arguments& headers, const Arguments& getArguments, const std::string& postData); void Register(const std::string& path, GetHandler handler); void Register(const std::string& path, PutHandler handler); void Register(const std::string& path, PostHandler handler); void Register(const std::string& path, DeleteHandler handler); }; } Orthanc-0.7.2/Core/RestApi/RestApiOutput.cpp0000644000000000000000000001037212237177136017013 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "RestApiOutput.h" #include #include "../OrthancException.h" namespace Orthanc { RestApiOutput::RestApiOutput(HttpOutput& output) : output_(output) { alreadySent_ = false; } RestApiOutput::~RestApiOutput() { if (!alreadySent_) { output_.SendHeader(HttpStatus_400_BadRequest); } } void RestApiOutput::CheckStatus() { if (alreadySent_) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } } void RestApiOutput::AnswerFile(HttpFileSender& sender) { CheckStatus(); sender.Send(output_); alreadySent_ = true; } void RestApiOutput::AnswerJson(const Json::Value& value) { CheckStatus(); Json::StyledWriter writer; std::string s = writer.write(value); output_.AnswerBufferWithContentType(s, "application/json", cookies_); alreadySent_ = true; } void RestApiOutput::AnswerBuffer(const std::string& buffer, const std::string& contentType) { CheckStatus(); output_.AnswerBufferWithContentType(buffer, contentType, cookies_); alreadySent_ = true; } void RestApiOutput::AnswerBuffer(const void* buffer, size_t length, const std::string& contentType) { CheckStatus(); output_.AnswerBufferWithContentType(buffer, length, contentType, cookies_); alreadySent_ = true; } void RestApiOutput::Redirect(const std::string& path) { CheckStatus(); output_.Redirect(path); alreadySent_ = true; } void RestApiOutput::SignalError(HttpStatus status) { if (status != HttpStatus_403_Forbidden && status != HttpStatus_415_UnsupportedMediaType) { throw OrthancException("This HTTP status is not allowed in a REST API"); } CheckStatus(); output_.SendHeader(status); alreadySent_ = true; } 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); } cookies_[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); } } Orthanc-0.7.2/Core/RestApi/RestApiOutput.h0000644000000000000000000000514712237177136016464 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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_; bool alreadySent_; HttpHandler::Arguments cookies_; void CheckStatus(); public: RestApiOutput(HttpOutput& output); ~RestApiOutput(); HttpOutput& GetLowLevelOutput() { return output_; } void MarkLowLevelOutputDone() { alreadySent_ = true; } void AnswerFile(HttpFileSender& sender); void AnswerJson(const Json::Value& value); void AnswerBuffer(const std::string& buffer, const std::string& contentType); void AnswerBuffer(const void* buffer, size_t length, const std::string& contentType); void SignalError(HttpStatus status); 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); }; } Orthanc-0.7.2/Core/RestApi/RestApiPath.cpp0000644000000000000000000000706012237177136016407 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "RestApiPath.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(Components& components, UriComponents& trailing, const std::string& uriRaw) const { UriComponents uri; Toolbox::SplitUriComponents(uri, uriRaw); return Match(components, trailing, uri); } bool RestApiPath::Match(Components& components, UriComponents& trailing, const UriComponents& uri) const { 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 { Components components; UriComponents trailing; return Match(components, trailing, uri); } } Orthanc-0.7.2/Core/RestApi/RestApiPath.h0000644000000000000000000000423112237177136016051 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 namespace Orthanc { class RestApiPath { private: UriComponents uri_; bool hasTrailing_; std::vector components_; public: typedef std::map Components; RestApiPath(const std::string& uri); // This version is slower bool Match(Components& components, UriComponents& trailing, const std::string& uriRaw) const; bool Match(Components& components, UriComponents& trailing, const UriComponents& uri) const; bool Match(const UriComponents& uri) const; }; } Orthanc-0.7.2/Core/SQLite/Connection.cpp0000644000000000000000000002326612237177136016122 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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. **/ #include "Connection.h" #include #include #include #include #include namespace Orthanc { namespace SQLite { Connection::Connection() : db_(NULL), transactionNesting_(0), needsRollback_(false) { } Connection::~Connection() { Close(); } void Connection::CheckIsOpen() const { if (!db_) { throw OrthancException("SQLite: The database is not opened"); } } void Connection::Open(const std::string& path) { if (db_) { throw OrthancException("SQLite: Connection is already open"); } int err = sqlite3_open(path.c_str(), &db_); if (err != SQLITE_OK) { Close(); db_ = NULL; throw OrthancException("SQLite: Unable to open the database"); } // 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 OrthancException("SQLite: This cached statement is already being referred to"); } return *i->second; } else { StatementReference* statement = new StatementReference(db_, sql); cachedStatements_[id] = statement; return *statement; } } bool Connection::Execute(const char* sql) { VLOG(1) << "SQLite::Connection::Execute " << sql; CheckIsOpen(); int error = sqlite3_exec(db_, sql, NULL, NULL, NULL); if (error == SQLITE_ERROR) { throw OrthancException("SQLite Execute error: " + std::string(sqlite3_errmsg(db_))); } 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 OrthancException("Rolling back a nonexistent transaction"); } transactionNesting_--; if (transactionNesting_ > 0) { // Mark the outermost transaction as needing rollback. needsRollback_ = true; return; } DoRollback(); } bool Connection::CommitTransaction() { if (!transactionNesting_) { throw OrthancException("Committing a nonexistent transaction"); } 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 OrthancException("SQLite: Unable to register a function"); } return func; } void Connection::FlushToDisk() { VLOG(1) << "SQLite::Connection::FlushToDisk"; int err = sqlite3_wal_checkpoint(db_, NULL); if (err != SQLITE_OK) { throw OrthancException("SQLite: Unable to flush the database"); } } } } Orthanc-0.7.2/Core/SQLite/Connection.h0000644000000000000000000001336112237177136015562 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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 #include #include struct sqlite3; struct sqlite3_stmt; #define SQLITE_FROM_HERE SQLite::StatementId(__FILE__, __LINE__) namespace Orthanc { namespace SQLite { class Connection : boost::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(); }; } } Orthanc-0.7.2/Core/SQLite/FunctionContext.cpp0000644000000000000000000000703612237177136017152 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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. **/ #include "FunctionContext.h" #include namespace Orthanc { namespace SQLite { FunctionContext::FunctionContext(struct sqlite3_context* context, int argc, struct ::Mem** 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 OrthancException(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]))); } 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(), str.size(), SQLITE_TRANSIENT); } } } Orthanc-0.7.2/Core/SQLite/FunctionContext.h0000644000000000000000000000534512237177136016620 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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 #include "Statement.h" struct sqlite3_context; struct Mem; // This corresponds to the opaque type "sqlite3_value" namespace Orthanc { namespace SQLite { class FunctionContext : public boost::noncopyable { friend class Connection; private: struct sqlite3_context* context_; unsigned int argc_; struct ::Mem** argv_; void CheckIndex(unsigned int index) const; public: FunctionContext(struct sqlite3_context* context, int argc, struct ::Mem** 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; void SetNullResult(); void SetIntResult(int value); void SetDoubleResult(double value); void SetStringResult(const std::string& str); }; } } Orthanc-0.7.2/Core/SQLite/IScalarFunction.h0000644000000000000000000000375312237177136016513 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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 "FunctionContext.h" namespace Orthanc { namespace SQLite { class IScalarFunction : public boost::noncopyable { public: virtual ~IScalarFunction() { } virtual const char* GetName() const = 0; virtual unsigned int GetCardinality() const = 0; virtual void Compute(FunctionContext& context) = 0; }; } } Orthanc-0.7.2/Core/SQLite/README.txt0000644000000000000000000000152412237177136015006 0ustar 00000000000000Introduction ============ 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. 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. Orthanc-0.7.2/Core/SQLite/Statement.cpp0000644000000000000000000002216012237177136015757 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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. **/ #include "Statement.h" #include "Connection.h" #include "../Toolbox.h" #include #include #include #include namespace Orthanc { namespace SQLite { int Statement::CheckError(int err) const { bool succeeded = (err == SQLITE_OK || err == SQLITE_ROW || err == SQLITE_DONE); if (!succeeded) { throw OrthancException("SQLite error code " + boost::lexical_cast(err)); } return err; } void Statement::CheckOk(int err) const { if (err == SQLITE_RANGE) { // Binding to a non-existent variable is evidence of a serious error. throw OrthancException("Bind value out of range"); } else if (err != SQLITE_OK) { throw OrthancException("SQLite error code " + boost::lexical_cast(err)); } } Statement::Statement(Connection& database, const StatementId& id, const std::string& sql) : reference_(database.GetCachedStatement(id, sql.c_str())) { Reset(true); } Statement::Statement(Connection& database, const StatementId& id, const char* sql) : reference_(database.GetCachedStatement(id, sql)) { Reset(true); } Statement::Statement(Connection& database, const std::string& sql) : reference_(database.GetWrappedObject(), sql.c_str()) { } Statement::Statement(Connection& database, const char* sql) : reference_(database.GetWrappedObject(), sql) { } bool Statement::Run() { VLOG(1) << "SQLite::Statement::Run " << sqlite3_sql(GetStatement()); return CheckError(sqlite3_step(GetStatement())) == SQLITE_DONE; } bool Statement::Step() { VLOG(1) << "SQLite::Statement::Step " << sqlite3_sql(GetStatement()); return CheckError(sqlite3_step(GetStatement())) == 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)); } 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)); } void Statement::BindInt64(int col, int64_t val) { CheckOk(sqlite3_bind_int64(GetStatement(), col + 1, val)); } void Statement::BindDouble(int col, double val) { CheckOk(sqlite3_bind_double(GetStatement(), col + 1, val)); } void Statement::BindCString(int col, const char* val) { CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val, -1, SQLITE_TRANSIENT)); } void Statement::BindString(int col, const std::string& val) { CheckOk(sqlite3_bind_text(GetStatement(), col + 1, val.data(), val.size(), SQLITE_TRANSIENT)); } /*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)); } 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)); Toolbox::ToLowerCase(column_type); 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)); } } } Orthanc-0.7.2/Core/SQLite/Statement.h0000644000000000000000000001330412237177136015424 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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 "../OrthancException.h" #include "StatementId.h" #include "StatementReference.h" #include #include #include #if ORTHANC_BUILD_UNIT_TESTS == 1 #include #endif struct sqlite3_stmt; 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 boost::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) const; void CheckOk(int err) const; struct sqlite3_stmt* GetStatement() const { return reference_.GetWrappedObject(); } // 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); 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; }; } } Orthanc-0.7.2/Core/SQLite/StatementId.cpp0000644000000000000000000000375212237177136016242 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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. **/ #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; } } } Orthanc-0.7.2/Core/SQLite/StatementId.h0000644000000000000000000000404512237177136015703 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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; }; } } Orthanc-0.7.2/Core/SQLite/StatementReference.cpp0000644000000000000000000000757212237177136017610 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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. **/ #include "StatementReference.h" #include "../OrthancException.h" #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 OrthancException(ErrorCode_ParameterOutOfRange); } root_ = NULL; refCount_ = 0; int error = sqlite3_prepare_v2(database, sql, -1, &statement_, NULL); if (error != SQLITE_OK) { throw OrthancException("SQLite: " + std::string(sqlite3_errmsg(database))); } 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 LOG(ERROR) << "Bad value of the reference counter"; } 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 LOG(ERROR) << "Bad value of the reference counter"; } else { root_->refCount_--; } } } uint32_t StatementReference::GetReferenceCount() const { return refCount_; } } } Orthanc-0.7.2/Core/SQLite/StatementReference.h0000644000000000000000000000504012237177136017241 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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 #include #include #include struct sqlite3; struct sqlite3_stmt; namespace Orthanc { namespace SQLite { class StatementReference : boost::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_; } }; } } Orthanc-0.7.2/Core/SQLite/Transaction.cpp0000644000000000000000000000602612237177136016303 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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. **/ #include "Transaction.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 OrthancException("SQLite: Beginning a transaction twice!"); } isOpen_ = connection_.BeginTransaction(); if (!isOpen_) { throw OrthancException("SQLite: Unable to create a transaction"); } } void Transaction::Rollback() { if (!isOpen_) { throw OrthancException("SQLite: Attempting to roll back a nonexistent transaction. " "Did you remember to call Begin()?"); } isOpen_ = false; connection_.RollbackTransaction(); } void Transaction::Commit() { if (!isOpen_) { throw OrthancException("SQLite: Attempting to roll back a nonexistent transaction. " "Did you remember to call Begin()?"); } isOpen_ = false; if (!connection_.CommitTransaction()) { throw OrthancException("SQLite: Failure when committing the transaction"); } } } } Orthanc-0.7.2/Core/SQLite/Transaction.h0000644000000000000000000000533312237177136015750 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 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" namespace Orthanc { namespace SQLite { class Transaction : public boost::noncopyable { 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); ~Transaction(); // Returns true when there is a transaction that has been successfully begun. bool IsOpen() const { return isOpen_; } // 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. void Begin(); // Rolls back the transaction. This will happen automatically if you do // nothing when the transaction goes out of scope. void Rollback(); // Commits the transaction, returning true on success. void Commit(); }; } } Orthanc-0.7.2/Core/Toolbox.cpp0000644000000000000000000004314112237177136014302 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Toolbox.h" #include "OrthancException.h" #include #include #include #include #include #include #include #include #include #if defined(_WIN32) #include #endif #if defined(__APPLE__) && defined(__MACH__) #include /* _NSGetExecutablePath */ #include /* PATH_MAX */ #endif #if defined(__linux) #include /* PATH_MAX */ #include #include #endif #if BOOST_HAS_LOCALE == 1 #include #else #include #endif #include "../Resources/md5/md5.h" #include "../Resources/base64/base64.h" #ifdef _MSC_VER // Patch for the missing "_strtoll" symbol when compiling with Visual Studio 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 BOOST_HAS_LOCALE == 0 namespace { class IconvRabi { private: iconv_t context_; public: IconvRabi(const char* tocode, const char* fromcode) { context_ = iconv_open(tocode, fromcode); if (!context_) { throw Orthanc::OrthancException("Unknown code page"); } } ~IconvRabi() { iconv_close(context_); } std::string Convert(const std::string& source) { if (source.size() == 0) { return ""; } std::string result; char* sourcePos = const_cast(&source[0]); size_t sourceLeft = source.size(); std::vector storage(source.size() + 10); while (sourceLeft > 0) { char* tmp = &storage[0]; size_t outputLeft = storage.size(); size_t err = iconv(context_, &sourcePos, &sourceLeft, &tmp, &outputLeft); if (err < 0) { throw Orthanc::OrthancException("Bad character in sequence"); } size_t count = storage.size() - outputLeft; result += std::string(&storage[0], count); } return result; } }; } #endif namespace Orthanc { static bool finish; #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) { finish = true; } #endif void Toolbox::Sleep(uint32_t seconds) { #if defined(_WIN32) ::Sleep(static_cast(seconds) * static_cast(1000)); #elif defined(__linux) usleep(static_cast(seconds) * static_cast(1000000)); #else #error Support your platform here #endif } void Toolbox::USleep(uint64_t microSeconds) { #if defined(_WIN32) ::Sleep(static_cast(microSeconds / static_cast(1000))); #elif defined(__linux) usleep(microSeconds); #else #error Support your platform here #endif } void Toolbox::ServerBarrier() { #if defined(_WIN32) SetConsoleCtrlHandler(ConsoleControlHandler, true); #else signal(SIGINT, SignalHandler); signal(SIGQUIT, SignalHandler); #endif finish = false; while (!finish) { USleep(100000); } #if defined(_WIN32) SetConsoleCtrlHandler(ConsoleControlHandler, false); #else signal(SIGINT, NULL); signal(SIGQUIT, NULL); #endif } 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::ReadFile(std::string& content, const std::string& path) { boost::filesystem::ifstream f; f.open(path, std::ifstream::in | std::ifstream::binary); if (!f.good()) { throw OrthancException(ErrorCode_InexistentFile); } // 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); content.resize(size); if (size != 0) { f.read(reinterpret_cast(&content[0]), size); } f.close(); } void Toolbox::WriteFile(const std::string& content, const std::string& path) { boost::filesystem::ofstream f; f.open(path, std::ofstream::binary); if (!f.good()) { throw OrthancException(ErrorCode_CannotWriteFile); } if (content.size() != 0) { f.write(content.c_str(), content.size()); } f.close(); } void Toolbox::RemoveFile(const std::string& path) { if (boost::filesystem::exists(path)) { if (boost::filesystem::is_regular_file(path)) boost::filesystem::remove(path); else throw OrthancException("The path is not a regular file: " + path); } } 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); } } } 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::AutodetectMimeType(const std::string& path) { std::string contentType; size_t lastDot = path.rfind('.'); size_t lastSlash = path.rfind('/'); if (lastDot == std::string::npos || (lastSlash != std::string::npos && lastDot < lastSlash)) { // No trailing dot, unable to detect the content type } else { const char* extension = &path[lastDot + 1]; // http://en.wikipedia.org/wiki/Mime_types // Text types if (!strcmp(extension, "txt")) contentType = "text/plain"; else if (!strcmp(extension, "html")) contentType = "text/html"; else if (!strcmp(extension, "xml")) contentType = "text/xml"; else if (!strcmp(extension, "css")) contentType = "text/css"; // Application types else if (!strcmp(extension, "js")) contentType = "application/javascript"; else if (!strcmp(extension, "json")) contentType = "application/json"; else if (!strcmp(extension, "pdf")) contentType = "application/pdf"; // Images types else if (!strcmp(extension, "jpg") || !strcmp(extension, "jpeg")) contentType = "image/jpeg"; else if (!strcmp(extension, "gif")) contentType = "image/gif"; else if (!strcmp(extension, "png")) contentType = "image/png"; } return contentType; } 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; } } uint64_t Toolbox::GetFileSize(const std::string& path) { try { return static_cast(boost::filesystem::file_size(path)); } catch (boost::filesystem::filesystem_error) { throw OrthancException(ErrorCode_InexistentFile); } } 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) { md5_state_s state; md5_init(&state); if (data.size() > 0) { md5_append(&state, reinterpret_cast(&data[0]), static_cast(data.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(actualHash[i] / 16); result[2 * i + 1] = GetHexadecimalCharacter(actualHash[i] % 16); } } std::string Toolbox::EncodeBase64(const std::string& data) { return base64_encode(data); } std::string Toolbox::DecodeBase64(const std::string& data) { return base64_decode(data); } #if defined(_WIN32) std::string Toolbox::GetPathToExecutable() { // 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) std::string Toolbox::GetPathToExecutable() { std::vector buffer(PATH_MAX + 1); ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1); if (bytes == 0) { throw OrthancException("Unable to get the path to the executable"); } return std::string(&buffer[0]); } #elif defined(__APPLE__) && defined(__MACH__) std::string Toolbox::GetPathToExecutable() { char pathbuf[PATH_MAX + 1]; unsigned int bufsize = static_cast(sizeof(pathbuf)); _NSGetExecutablePath( pathbuf, &bufsize); return std::string(pathbuf); } #else #error Support your platform here #endif std::string Toolbox::GetDirectoryOfExecutable() { boost::filesystem::path p(GetPathToExecutable()); return p.parent_path().string(); } std::string Toolbox::ConvertToUtf8(const std::string& source, const char* fromEncoding) { #if BOOST_HAS_LOCALE == 1 try { return boost::locale::conv::to_utf(source, fromEncoding); } catch (std::runtime_error&) { // Bad input string or bad encoding return ConvertToAscii(source); } #else IconvRabi iconv("UTF-8", fromEncoding); try { return iconv.Convert(source); } catch (OrthancException) { return ConvertToAscii(source); } #endif } std::string Toolbox::ConvertToAscii(const std::string& source) { std::string result; result.reserve(source.size()); for (size_t i = 0; i < source.size(); i++) { if (source[i] < 128 && source[i] >= 0 && !iscntrl(source[i])) { result.push_back(source[i]); } } return result; } void Toolbox::ComputeSHA1(std::string& result, const std::string& data) { boost::uuids::detail::sha1 sha1; if (data.size() > 0) { sha1.process_bytes(&data[0], 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]); } bool Toolbox::IsSHA1(const std::string& str) { if (str.size() != 44) { return false; } for (unsigned int i = 0; i < 44; i++) { if (i == 8 || i == 17 || i == 26 || i == 35) { if (str[i] != '-') return false; } else { if (!isalnum(str[i])) return false; } } return true; } std::string Toolbox::GetNowIsoString() { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); return boost::posix_time::to_iso_string(now); } 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/ uint8_t buffer[4]; buffer[0] = 0x00; buffer[1] = 0x01; buffer[2] = 0x02; buffer[3] = 0x03; switch (*((uint32_t *)buffer)) { 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) { result.clear(); 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); } } Orthanc-0.7.2/Core/Toolbox.h0000644000000000000000000000706512237177136013754 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 { typedef std::vector UriComponents; class NullType { }; namespace Toolbox { void ServerBarrier(); void ToUpperCase(std::string& s); void ToLowerCase(std::string& s); void ReadFile(std::string& content, const std::string& path); void WriteFile(const std::string& content, const std::string& path); void Sleep(uint32_t seconds); void USleep(uint64_t microSeconds); void RemoveFile(const std::string& path); void SplitUriComponents(UriComponents& components, const std::string& uri); bool IsChildUri(const UriComponents& baseUri, const UriComponents& testedUri); std::string AutodetectMimeType(const std::string& path); std::string FlattenUri(const UriComponents& components, size_t fromLevel = 0); uint64_t GetFileSize(const std::string& path); void ComputeMD5(std::string& result, const std::string& data); void ComputeSHA1(std::string& result, const std::string& data); bool IsSHA1(const std::string& str); std::string DecodeBase64(const std::string& data); std::string EncodeBase64(const std::string& data); std::string GetPathToExecutable(); std::string GetDirectoryOfExecutable(); std::string ConvertToUtf8(const std::string& source, const char* fromEncoding); std::string ConvertToAscii(const std::string& source); std::string StripSpaces(const std::string& source); std::string GetNowIsoString(); // 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); } } Orthanc-0.7.2/Core/Uuid.cpp0000644000000000000000000000732412237177136013565 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Uuid.h" // http://stackoverflow.com/a/1626302 extern "C" { #ifdef WIN32 #include #else #include #endif } #include namespace Orthanc { namespace Toolbox { std::string 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; } bool 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 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)); } static std::string CreateTemporaryPath(const char* extension) { #if BOOST_HAS_FILESYSTEM_V3 == 1 boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path(); #elif defined(__linux__) boost::filesystem::path tmpDir("/tmp"); #else #error Support your platform here #endif // We use UUID to create unique path to temporary files std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid(); if (extension != NULL) { filename.append(extension); } tmpDir /= filename; return tmpDir.string(); } TemporaryFile::TemporaryFile() : path_(CreateTemporaryPath(NULL)) { } TemporaryFile::TemporaryFile(const char* extension) : path_(CreateTemporaryPath(extension)) { } TemporaryFile::~TemporaryFile() { boost::filesystem::remove(path_); } } } Orthanc-0.7.2/Core/Uuid.h0000644000000000000000000000451412237177136013230 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 /** * 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 **/ namespace Orthanc { namespace Toolbox { std::string GenerateUuid(); bool IsUuid(const std::string& str); bool StartsWithUuid(const std::string& str); class TemporaryFile { private: std::string path_; public: TemporaryFile(); TemporaryFile(const char* extension); ~TemporaryFile(); const std::string& GetPath() const { return path_; } }; } } Orthanc-0.7.2/INSTALL0000644000000000000000000000471012237177136012310 0ustar 00000000000000Orthanc - A Lightweight, RESTful DICOM Server ============================================= Dependencies ------------ 1) CMake: Orthanc uses CMake (http://www.cmake.org/) to automate its building process. 2) Python: Some code is autogenerated through Python (http://www.python.org/). 3) Mercurial: To use the cutting edge code, a Mercurial client must be installed (http://mercurial.selenic.com/). We recommand TortoiseHg. W) 7-Zip: For the native build under Windows, the 7-Zip tool is used to uncompress the third-party packages (http://www.7-zip.org/). You thus have to download and install CMake, Python, Mercurial and possibly 7-Zip first. The path to their executable must be in the "PATH" environment variable. The other third party dependencies are automatically downloaded by the CMake scripts. The downloaded packages are stored in the "ThirdPartyDownloads" directory. Building Orthanc at a glance ---------------------------- To build Orthanc, you must: 1) Download the source code (either using Mercurial, or through the released versions). For the examples below, we assume the source directory is "~/Orthanc". 2) Create a build directory. For the examples below, we assume the build directory is "~/OrthancBuild". Native Linux Compilation ------------------------ See the file "LinuxCompilation.txt". Native Windows build with Microsoft Visual Studio 2005 ------------------------------------------------------ # cd [...]\OrthancBuild # cmake -DSTANDALONE_BUILD=ON -G "Visual Studio 8 2005" [...]\Orthanc Then open the "[...]/OrthancBuild/Orthanc.sln" with Visual Studio. NOTES: * More recent versions of Visual Studio should also work. * You will have to install the Platform SDK (version 6 or above) for Visual Studio 2005: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK. Read the CMake FAQ: http://goo.gl/By90B Cross-Compilation for Windows under Linux ----------------------------------------- To cross-compile Windows binaries under Linux using MinGW, please use the following command: # cd ~/OrthancBuild # cmake -DCMAKE_TOOLCHAIN_FILE=~/Orthanc/Resources/MinGWToolchain.cmake -DSTANDALONE_BUILD=ON -DCMAKE_BUILD_TYPE=Debug ~/Orthanc # make Native Windows build with MinGW (VERY SLOW) ------------------------------------------- # cd [...]\OrthancBuild # cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug [...]\Orthanc # mingw32-make Orthanc-0.7.2/LinuxCompilation.txt0000644000000000000000000001235612237177136015323 0ustar 00000000000000This file is a complement to "INSTALL", which contains instructions that are specific to Linux. Static linking for Linux ======================== The most simple way of building Orthanc under Linux consists in statically linking against all the third-party dependencies. In this case, the system-wide libraries will not be used. The build tool (CMake) will download the sources of all the required packages and automatically compile them. This process should work on all the Linux distributions. To build binaries with debug information: # cd ~/OrthancBuild # cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Debug ~/Orthanc # make # make doc To build a release version: # cd ~/OrthancBuild # cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Release ~/Orthanc # make # make doc Note: When the "STATIC_BUILD" option is set to "ON", the build tool will not ask you the permission to download packages from the Internet. Use system-wide libraries under Linux ===================================== Under Linux, by default, Orthanc links against the shared libraries of your system (the "STATIC_BUILD" option is set to "OFF"). This greatly speeds up the compilation. This is also required when building packages for Linux distributions. Because using system libraries is the default behavior, you just have to use: # cd ~/OrthancBuild # cmake -DCMAKE_BUILD_TYPE=Debug ~/Orthanc # make However, on some Linux distributions, it is still required to download and static link against some third-party dependencies, e.g. when the system-wide library is not shipped or is outdated. Because of difference in the packaging of the various Linux distribution, it is also sometimes required to fine-tune some options. You will find below build instructions for specific Linux distributions. Distributions tagged by "SUPPORTED" are tested by Sébastien Jodogne. Distributions tagged by "CONTRIBUTED" come from Orthanc users. SUPPORTED - Debian Squeeze (6.0) -------------------------------- # sudo apt-get install build-essential unzip cmake mercurial \ uuid-dev libcurl4-openssl-dev liblua5.1-0-dev \ libgoogle-glog-dev libpng-dev libgtest-dev \ libsqlite3-dev libssl-dev zlib1g-dev # cmake -DALLOW_DOWNLOADS=ON \ -DUSE_SYSTEM_BOOST=OFF \ -DUSE_SYSTEM_DCMTK=OFF \ -DUSE_SYSTEM_MONGOOSE=OFF \ -DUSE_SYSTEM_JSONCPP=OFF \ ~/Orthanc SUPPORTED - Debian Jessie/Sid ----------------------------- # sudo apt-get install build-essential unzip cmake mercurial \ uuid-dev libcurl4-openssl-dev liblua5.1-0-dev \ libgoogle-glog-dev libgtest-dev libpng-dev \ libsqlite3-dev libssl-dev zlib1g-dev \ libdcmtk2-dev libboost-all-dev libwrap0-dev # cmake -DALLOW_DOWNLOADS=ON \ -DUSE_SYSTEM_MONGOOSE=OFF \ -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \ -DDCMTK_DICTIONARY_DIR:PATH=/usr/share/libdcmtk2 \ ~/Orthanc Note: Have also a look at the official package: http://anonscm.debian.org/viewvc/debian-med/trunk/packages/orthanc/trunk/debian/ SUPPORTED - Ubuntu 12.04 LTS ---------------------------- # sudo apt-get install build-essential unzip cmake mercurial \ uuid-dev libcurl4-openssl-dev liblua5.1-0-dev \ libgtest-dev libpng-dev libsqlite3-dev libssl-dev \ zlib1g-dev libdcmtk2-dev libboost-all-dev libwrap0-dev # cmake "-DDCMTK_LIBRARIES=wrap;oflog" \ -DALLOW_DOWNLOADS=ON \ -DUSE_SYSTEM_MONGOOSE=OFF \ -DUSE_SYSTEM_JSONCPP=OFF \ -DUSE_SYSTEM_GOOGLE_LOG=OFF \ -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \ ~/Orthanc SUPPORTED - Ubuntu 12.10 ------------------------ # sudo apt-get install build-essential unzip cmake mercurial \ uuid-dev libcurl4-openssl-dev liblua5.1-0-dev \ libgoogle-glog-dev libgtest-dev libpng-dev \ libsqlite3-dev libssl-dev zlib1g-dev \ libdcmtk2-dev libboost-all-dev libwrap0-dev # cmake "-DDCMTK_LIBRARIES=wrap;oflog" \ -DALLOW_DOWNLOADS=ON \ -DUSE_SYSTEM_MONGOOSE=OFF \ -DUSE_SYSTEM_JSONCPP=OFF \ -DUSE_GTEST_DEBIAN_SOURCE_PACKAGE=ON \ ~/Orthanc SUPPORTED - Fedora 18 --------------------- # sudo yum install make automake gcc gcc-c++ python cmake \ boost-devel curl-devel dcmtk-devel glog-devel \ gtest-devel libpng-devel libsqlite3x-devel libuuid-devel \ mongoose-devel openssl-devel jsoncpp-devel lua-devel # cmake ~/Orthanc Note: Have also a look at the official package: http://pkgs.fedoraproject.org/cgit/orthanc.git/tree/?h=f18 Other Linux distributions? -------------------------- Please send us your build instructions (by a mail to s.jodogne@gmail.com)! You can find build instructions for Orthanc up to 0.7.0 on the following Wiki page: https://code.google.com/p/orthanc/wiki/LinuxCompilationUpTo070 These instructions will not work as such beyond Orthanc 0.7.0, but they might give indications. Using ccache ============ Under Linux, you also have the opportunity to use "ccache" to dramatically decrease the compilation time when rebuilding Orthanc. This is especially useful for developers. To this end, you would use: # CC="ccache gcc" CXX="ccache g++" cmake ~/Orthanc [Other Options] Orthanc-0.7.2/NEWS0000644000000000000000000001445412237177136011764 0ustar 00000000000000Pending changes in the mainline =============================== 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 connexion) * 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 anymization 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 Logging * 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 Orthanc-0.7.2/OrthancCppClient/Instance.cpp0000644000000000000000000001453312237177136016733 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Instance.h" #include "OrthancConnection.h" #include namespace OrthancClient { void Instance::DownloadImage() { if (reader_.get() == NULL) { const char* suffix; switch (mode_) { case Orthanc::ImageExtractionMode_Preview: suffix = "preview"; break; case Orthanc::ImageExtractionMode_UInt8: suffix = "image-uint8"; break; case Orthanc::ImageExtractionMode_UInt16: suffix = "image-uint16"; break; case Orthanc::ImageExtractionMode_Int16: suffix = "image-int16"; break; default: throw OrthancClientException(Orthanc::ErrorCode_NotImplemented); } Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/instances/" + id_ + "/" + suffix); std::string png; if (!client.Apply(png)) { throw OrthancClientException(Orthanc::ErrorCode_NotImplemented); } reader_.reset(new Orthanc::PngReader); reader_->ReadFromMemory(png); } } void Instance::DownloadDicom() { if (dicom_.get() == NULL) { Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/instances/" + id_ + "/file"); dicom_.reset(new std::string); if (!client.Apply(*dicom_)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } } Instance::Instance(const OrthancConnection& connection, const char* id) : connection_(connection), id_(id), mode_(Orthanc::ImageExtractionMode_Int16) { Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/instances/" + id_ + "/simplified-tags"); Json::Value v; if (!client.Apply(tags_)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } const char* Instance::GetTagAsString(const char* tag) const { if (tags_.isMember(tag)) { return tags_[tag].asCString(); } else { throw OrthancClientException(Orthanc::ErrorCode_InexistentItem); } } float Instance::GetTagAsFloat(const char* tag) const { std::string value = GetTagAsString(tag); try { return boost::lexical_cast(value); } catch (boost::bad_lexical_cast) { throw OrthancClientException(Orthanc::ErrorCode_BadFileFormat); } } int Instance::GetTagAsInt(const char* tag) const { std::string value = GetTagAsString(tag); try { return boost::lexical_cast(value); } catch (boost::bad_lexical_cast) { throw OrthancClientException(Orthanc::ErrorCode_BadFileFormat); } } unsigned int Instance::GetWidth() { DownloadImage(); return reader_->GetWidth(); } unsigned int Instance::GetHeight() { DownloadImage(); return reader_->GetHeight(); } unsigned int Instance::GetPitch() { DownloadImage(); return reader_->GetPitch(); } Orthanc::PixelFormat Instance::GetPixelFormat() { DownloadImage(); return reader_->GetFormat(); } const void* Instance::GetBuffer() { DownloadImage(); return reader_->GetBuffer(); } const void* Instance::GetBuffer(unsigned int y) { DownloadImage(); return reader_->GetBuffer(y); } void Instance::DiscardImage() { reader_.reset(); } void Instance::DiscardDicom() { dicom_.reset(); } void Instance::SetImageExtractionMode(Orthanc::ImageExtractionMode mode) { if (mode_ == mode) { return; } DiscardImage(); mode_ = mode; } void Instance::SplitVectorOfFloats(std::vector& target, const char* tag) { const std::string value = GetTagAsString(tag); target.clear(); try { std::string tmp; for (size_t i = 0; i < value.size(); i++) { if (value[i] == '\\') { target.push_back(boost::lexical_cast(tmp)); tmp.clear(); } else { tmp.push_back(value[i]); } } target.push_back(boost::lexical_cast(tmp)); } catch (boost::bad_lexical_cast) { // Unable to parse the Image Orientation Patient. throw OrthancClientException(Orthanc::ErrorCode_BadFileFormat); } } const uint64_t Instance::GetDicomSize() { DownloadDicom(); assert(dicom_.get() != NULL); return dicom_->size(); } const void* Instance::GetDicom() { DownloadDicom(); assert(dicom_.get() != NULL); if (dicom_->size() == 0) { return NULL; } else { return &((*dicom_) [0]); } } } Orthanc-0.7.2/OrthancCppClient/Instance.h0000644000000000000000000001424312237177136016376 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "OrthancClientException.h" #include "../Core/IDynamicObject.h" #include "../Core/FileFormats/PngReader.h" namespace OrthancClient { class OrthancConnection; /** * {summary}{Connection to an instance stored in %Orthanc.} * {description}{This class encapsulates a connection to an image instance * from a remote instance of %Orthanc.} **/ class LAAW_API Instance : public Orthanc::IDynamicObject { private: const OrthancConnection& connection_; std::string id_; Json::Value tags_; std::auto_ptr reader_; Orthanc::ImageExtractionMode mode_; std::auto_ptr dicom_; void DownloadImage(); void DownloadDicom(); public: /** * {summary}{Create a connection to some image instance.} * {param}{connection The remote instance of %Orthanc.} * {param}{id The %Orthanc identifier of the image instance.} **/ Instance(const OrthancConnection& connection, const char* id); /** * {summary}{Get the %Orthanc identifier of this identifier.} * {returns}{The identifier.} **/ const char* GetId() const { return id_.c_str(); } /** * {summary}{Set the extraction mode for the 2D image corresponding to this instance.} * {param}{mode The extraction mode.} **/ void SetImageExtractionMode(Orthanc::ImageExtractionMode mode); /** * {summary}{Get the extraction mode for the 2D image corresponding to this instance.} * {returns}{The extraction mode.} **/ Orthanc::ImageExtractionMode GetImageExtractionMode() const { return mode_; } /** * {summary}{Get the string value of some DICOM tag of this instance.} * {param}{tag The name of the tag of interest.} * {returns}{The value of the tag.} **/ const char* GetTagAsString(const char* tag) const; /** * {summary}{Get the floating point value that is stored in some DICOM tag of this instance.} * {param}{tag The name of the tag of interest.} * {returns}{The value of the tag.} **/ float GetTagAsFloat(const char* tag) const; /** * {summary}{Get the integer value that is stored in some DICOM tag of this instance.} * {param}{tag The name of the tag of interest.} * {returns}{The value of the tag.} **/ int32_t GetTagAsInt(const char* tag) const; /** * {summary}{Get the width of the 2D image.} * {description}{Get the width of the 2D image that is encoded by this DICOM instance.} * {returns}{The width.} **/ uint32_t GetWidth(); /** * {summary}{Get the height of the 2D image.} * {description}{Get the height of the 2D image that is encoded by this DICOM instance.} * {returns}{The height.} **/ uint32_t GetHeight(); /** * {summary}{Get the number of bytes between two lines of the image (pitch).} * {description}{Get the number of bytes between two lines of the image in the memory buffer returned by GetBuffer(). This value depends on the extraction mode for the image.} * {returns}{The pitch.} **/ uint32_t GetPitch(); /** * {summary}{Get the format of the pixels of the 2D image.} * {description}{Return the memory layout that is used for the 2D image that is encoded by this DICOM instance. This value depends on the extraction mode for the image.} * {returns}{The pixel format.} **/ Orthanc::PixelFormat GetPixelFormat(); /** * {summary}{Access the memory buffer in which the raw pixels of the 2D image are stored.} * {returns}{A pointer to the memory buffer.} **/ const void* GetBuffer(); /** * {summary}{Access the memory buffer in which the raw pixels of some line of the 2D image are stored.} * {param}{y The line of interest.} * {returns}{A pointer to the memory buffer.} **/ const void* GetBuffer(uint32_t y); /** * {summary}{Get the size of the DICOM file corresponding to this instance.} * {returns}{The file size.} **/ const uint64_t GetDicomSize(); /** * {summary}{Get a pointer to the content of the DICOM file corresponding to this instance.} * {returns}{The DICOM file.} **/ const void* GetDicom(); /** * {summary}{Discard the downloaded 2D image, so as to make room in memory.} **/ void DiscardImage(); /** * {summary}{Discard the downloaded DICOM file, so as to make room in memory.} **/ void DiscardDicom(); LAAW_API_INTERNAL void SplitVectorOfFloats(std::vector& target, const char* tag); }; } Orthanc-0.7.2/OrthancCppClient/OrthancClientException.h0000644000000000000000000000404412237177136021244 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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/OrthancException.h" #include "SharedLibrary/Laaw/laaw.h" namespace OrthancClient { class OrthancClientException : public ::Laaw::LaawException { public: OrthancClientException(Orthanc::ErrorCode code) : LaawException(Orthanc::OrthancException::GetDescription(code)) { } OrthancClientException(const char* message) : LaawException(message) { } OrthancClientException(const std::string& message) : LaawException(message) { } }; } Orthanc-0.7.2/OrthancCppClient/OrthancConnection.cpp0000644000000000000000000000676012237177136020610 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "OrthancConnection.h" #include "../Core/Toolbox.h" namespace OrthancClient { void OrthancConnection::ReadPatients() { client_.SetMethod(Orthanc::HttpMethod_Get); client_.SetUrl(orthancUrl_ + "/patients"); Json::Value v; if (!client_.Apply(content_)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } Orthanc::IDynamicObject* OrthancConnection::GetFillerItem(size_t index) { Json::Value::ArrayIndex tmp = static_cast(index); std::string id = content_[tmp].asString(); return new Patient(*this, id.c_str()); } Patient& OrthancConnection::GetPatient(unsigned int index) { return dynamic_cast(patients_.GetItem(index)); } OrthancConnection::OrthancConnection(const char* orthancUrl) : orthancUrl_(orthancUrl), patients_(*this) { ReadPatients(); } OrthancConnection::OrthancConnection(const char* orthancUrl, const char* username, const char* password) : orthancUrl_(orthancUrl), patients_(*this) { client_.SetCredentials(username, password); ReadPatients(); } void OrthancConnection::Store(const void* dicom, uint64_t size) { if (size == 0) { return; } client_.SetMethod(Orthanc::HttpMethod_Post); client_.SetUrl(orthancUrl_ + "/instances"); // Copy the DICOM file in the POST body. TODO - Avoid memory copy client_.AccessPostData().resize(static_cast(size)); memcpy(&client_.AccessPostData()[0], dicom, static_cast(size)); Json::Value v; if (!client_.Apply(v)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } Reload(); } void OrthancConnection::StoreFile(const char* filename) { std::string content; Orthanc::Toolbox::ReadFile(content, filename); if (content.size() != 0) { Store(&content[0], content.size()); } } } Orthanc-0.7.2/OrthancCppClient/OrthancConnection.h0000644000000000000000000001447012237177136020252 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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/HttpClient.h" #include "Patient.h" namespace OrthancClient { /** * {summary}{Connection to an instance of %Orthanc.} * {description}{This class encapsulates a connection to a remote instance * of %Orthanc through its REST API.} **/ class LAAW_API OrthancConnection : public boost::noncopyable, private Orthanc::ArrayFilledByThreads::IFiller { private: Orthanc::HttpClient client_; std::string orthancUrl_; Orthanc::ArrayFilledByThreads patients_; Json::Value content_; void ReadPatients(); virtual size_t GetFillerSize() { return content_.size(); } virtual Orthanc::IDynamicObject* GetFillerItem(size_t index); public: /** * {summary}{Create a connection to an instance of %Orthanc.} * {param}{orthancUrl URL to which the REST API of %Orthanc is listening.} **/ OrthancConnection(const char* orthancUrl); /** * {summary}{Create a connection to an instance of %Orthanc, with authentication.} * {param}{orthancUrl URL to which the REST API of %Orthanc is listening.} * {param}{username The username.} * {param}{password The password.} **/ OrthancConnection(const char* orthancUrl, const char* username, const char* password); virtual ~OrthancConnection() { } /** * {summary}{Returns the number of threads for this connection.} * {description}{Returns the number of simultaneous connections * that are used when downloading information from this instance * of %Orthanc.} * {returns}{The number of threads.} **/ uint32_t GetThreadCount() const { return patients_.GetThreadCount(); } /** * {summary}{Sets the number of threads for this connection.} * {description}{Sets the number of simultaneous connections * that are used when downloading information from this instance * of %Orthanc.} * {param}{threadCount The number of threads.} **/ void SetThreadCount(uint32_t threadCount) { patients_.SetThreadCount(threadCount); } /** * {summary}{Reload the list of the patients.} * {description}{This method will reload the list of the patients from the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated.} **/ void Reload() { ReadPatients(); patients_.Invalidate(); } LAAW_API_INTERNAL const Orthanc::HttpClient& GetHttpClient() const { return client_; } /** * {summary}{Returns the URL of this instance of %Orthanc.} * {description}{Returns the URL of the remote %Orthanc instance to which this object is connected.} * {returns}{The URL.} **/ const char* GetOrthancUrl() const { return orthancUrl_.c_str(); } /** * {summary}{Returns the number of patients.} * {description}{Returns the number of patients that are stored in the remote instance of %Orthanc.} * {returns}{The number of patients.} **/ uint32_t GetPatientCount() { return patients_.GetSize(); } /** * {summary}{Get some patient.} * {description}{This method will return an object that contains information about some patient. The patients are indexed by a number between 0 (inclusive) and the result of GetPatientCount() (exclusive).} * {param}{index The index of the patient of interest.} * {returns}{The patient.} **/ Patient& GetPatient(uint32_t index); /** * {summary}{Delete some patient.} * {description}{Delete some patient from the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated.} * {param}{index The index of the patient of interest.} * {returns}{The patient.} **/ void DeletePatient(uint32_t index) { GetPatient(index).Delete(); Reload(); } /** * {summary}{Send a DICOM file.} * {description}{This method will store a DICOM file in the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated.} * {param}{filename Path to the DICOM file} **/ void StoreFile(const char* filename); /** * {summary}{Send a DICOM file that is contained inside a memory buffer.} * {description}{This method will store a DICOM file in the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated.} * {param}{dicom The memory buffer containing the DICOM file.} * {param}{size The size of the DICOM file.} **/ void Store(const void* dicom, uint64_t size); }; } Orthanc-0.7.2/OrthancCppClient/Patient.cpp0000644000000000000000000000600012237177136016561 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Patient.h" #include "OrthancConnection.h" namespace OrthancClient { void Patient::ReadPatient() { Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/patients/" + id_); Json::Value v; if (!client.Apply(patient_)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } Orthanc::IDynamicObject* Patient::GetFillerItem(size_t index) { Json::Value::ArrayIndex tmp = static_cast(index); std::string id = patient_["Studies"][tmp].asString(); return new Study(connection_, id.c_str()); } Patient::Patient(const OrthancConnection& connection, const char* id) : connection_(connection), id_(id), studies_(*this) { studies_.SetThreadCount(connection.GetThreadCount()); ReadPatient(); } const char* Patient::GetMainDicomTag(const char* tag, const char* defaultValue) const { if (patient_["MainDicomTags"].isMember(tag)) { return patient_["MainDicomTags"][tag].asCString(); } else { return defaultValue; } } void Patient::Delete() { Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetMethod(Orthanc::HttpMethod_Delete); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/patients/" + id_); std::string s; if (!client.Apply(s)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } } Orthanc-0.7.2/OrthancCppClient/Patient.h0000644000000000000000000001015012237177136016227 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Study.h" namespace OrthancClient { /** * {summary}{Connection to a patient stored in %Orthanc.} * {description}{This class encapsulates a connection to a patient * from a remote instance of %Orthanc.} **/ class LAAW_API Patient : public Orthanc::IDynamicObject, private Orthanc::ArrayFilledByThreads::IFiller { private: const OrthancConnection& connection_; std::string id_; Json::Value patient_; Orthanc::ArrayFilledByThreads studies_; void ReadPatient(); virtual size_t GetFillerSize() { return patient_["Studies"].size(); } virtual Orthanc::IDynamicObject* GetFillerItem(size_t index); public: /** * {summary}{Create a connection to some patient.} * {param}{connection The remote instance of %Orthanc.} * {param}{id The %Orthanc identifier of the patient.} **/ Patient(const OrthancConnection& connection, const char* id); /** * {summary}{Reload the studies of this patient.} * {description}{This method will reload the list of the studies of this patient. Pay attention to the fact that the studies that have been previously returned by GetStudy() will be invalidated.} **/ void Reload() { studies_.Reload(); } /** * {summary}{Return the number of studies for this patient.} * {returns}{The number of studies.} **/ uint32_t GetStudyCount() { return studies_.GetSize(); } /** * {summary}{Get some study of this patient.} * {description}{This method will return an object that contains information about some study. The studies are indexed by a number between 0 (inclusive) and the result of GetStudyCount() (exclusive).} * {param}{index The index of the study of interest.} * {returns}{The study.} **/ Study& GetStudy(uint32_t index) { return dynamic_cast(studies_.GetItem(index)); } /** * {summary}{Get the %Orthanc identifier of this patient.} * {returns}{The identifier.} **/ const char* GetId() const { return id_.c_str(); } /** * {summary}{Get the value of one of the main DICOM tags for this patient.} * {param}{tag The name of the tag of interest ("PatientName", "PatientID", "PatientSex" or "PatientBirthDate").} * {param}{defaultValue The default value to be returned if this tag does not exist.} * {returns}{The value of the tag.} **/ const char* GetMainDicomTag(const char* tag, const char* defaultValue) const; LAAW_API_INTERNAL void Delete(); }; } Orthanc-0.7.2/OrthancCppClient/Series.cpp0000644000000000000000000003247212237177136016423 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Series.h" #include "OrthancConnection.h" #include #include namespace OrthancClient { namespace { class SliceLocator { private: float normal_[3]; public: SliceLocator(Instance& someSlice) { /** * Compute the slice normal from Image Orientation Patient. * http://nipy.sourceforge.net/nibabel/dicom/dicom_orientation.html#dicom-z-from-slice * http://www.itk.org/pipermail/insight-users/2003-September/004762.html **/ std::vector cosines; someSlice.SplitVectorOfFloats(cosines, "ImageOrientationPatient"); if (cosines.size() != 6) { throw OrthancClientException(Orthanc::ErrorCode_BadFileFormat); } 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]; } /** * Compute the distance of some slice along the slice normal. **/ float ComputeSliceLocation(Instance& instance) const { std::vector ipp; instance.SplitVectorOfFloats(ipp, "ImagePositionPatient"); if (ipp.size() != 3) { throw OrthancClientException(Orthanc::ErrorCode_BadFileFormat); } float dist = 0; for (int i = 0; i < 3; i++) { dist += normal_[i] * ipp[i]; } return dist; } }; class ImageDownloadCommand : public Orthanc::ICommand { private: Orthanc::PixelFormat format_; Orthanc::ImageExtractionMode mode_; Instance& instance_; void* target_; size_t lineStride_; public: ImageDownloadCommand(Instance& instance, Orthanc::PixelFormat format, Orthanc::ImageExtractionMode mode, void* target, size_t lineStride) : format_(format), mode_(mode), instance_(instance), target_(target), lineStride_(lineStride) { instance_.SetImageExtractionMode(mode); } virtual bool Execute() { using namespace Orthanc; unsigned int width = instance_.GetHeight(); for (unsigned int y = 0; y < instance_.GetHeight(); y++) { uint8_t* p = reinterpret_cast(target_) + y * lineStride_; if (instance_.GetPixelFormat() == format_) { memcpy(p, instance_.GetBuffer(y), 2 * instance_.GetWidth()); } else if (instance_.GetPixelFormat() == PixelFormat_Grayscale8 && format_ == PixelFormat_RGB24) { const uint8_t* s = reinterpret_cast(instance_.GetBuffer(y)); for (unsigned int x = 0; x < width; x++, s++, p += 3) { p[0] = *s; p[1] = *s; p[2] = *s; } } else { throw OrthancClientException(ErrorCode_NotImplemented); } } // Do not keep the image in memory, as we are loading 3D images instance_.DiscardImage(); return true; } }; class ProgressToFloatListener : public Orthanc::ThreadedCommandProcessor::IListener { private: float* target_; public: ProgressToFloatListener(float* target) : target_(target) { } virtual void SignalProgress(unsigned int current, unsigned int total) { if (total == 0) { *target_ = 0; } else { *target_ = static_cast(current) / static_cast(total); } } virtual void SignalSuccess(unsigned int total) { *target_ = 1; } virtual void SignalFailure() { *target_ = 0; } virtual void SignalCancel() { *target_ = 0; } }; } void Series::Check3DImage() { if (!Is3DImage()) { throw OrthancClientException(Orthanc::ErrorCode_NotImplemented); } } bool Series::Is3DImageInternal() { try { if (GetInstanceCount() == 0) { return true; } Instance& i1 = GetInstance(0); for (unsigned int i = 0; i < GetInstanceCount(); i++) { Instance& i2 = GetInstance(i); if (std::string(i1.GetTagAsString("Columns")) != std::string(i2.GetTagAsString("Columns")) || std::string(i1.GetTagAsString("Rows")) != std::string(i2.GetTagAsString("Rows")) || std::string(i1.GetTagAsString("ImageOrientationPatient")) != std::string(i2.GetTagAsString("ImageOrientationPatient")) || std::string(i1.GetTagAsString("SliceThickness")) != std::string(i2.GetTagAsString("SliceThickness")) || std::string(i1.GetTagAsString("PixelSpacing")) != std::string(i2.GetTagAsString("PixelSpacing"))) { return false; } } SliceLocator locator(GetInstance(0)); std::set l; for (unsigned int i = 0; i < GetInstanceCount(); i++) { l.insert(locator.ComputeSliceLocation(GetInstance(i))); } return l.size() == GetInstanceCount(); } catch (OrthancClientException) { return false; } } void Series::ReadSeries() { Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/series/" + id_); Json::Value v; if (!client.Apply(series_)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } Orthanc::IDynamicObject* Series::GetFillerItem(size_t index) { Json::Value::ArrayIndex tmp = static_cast(index); std::string id = series_["Instances"][tmp].asString(); return new Instance(connection_, id.c_str()); } Series::Series(const OrthancConnection& connection, const char* id) : connection_(connection), id_(id), instances_(*this) { ReadSeries(); status_ = Status3DImage_NotTested; url_ = std::string(connection_.GetOrthancUrl()) + "/series/" + id_; isVoxelSizeRead_ = false; voxelSizeX_ = 0; voxelSizeY_ = 0; voxelSizeZ_ = 0; instances_.SetThreadCount(connection.GetThreadCount()); } bool Series::Is3DImage() { if (status_ == Status3DImage_NotTested) { status_ = Is3DImageInternal() ? Status3DImage_True : Status3DImage_False; } return status_ == Status3DImage_True; } unsigned int Series::GetInstanceCount() { return instances_.GetSize(); } Instance& Series::GetInstance(unsigned int index) { return dynamic_cast(instances_.GetItem(index)); } unsigned int Series::GetWidth() { Check3DImage(); if (GetInstanceCount() == 0) return 0; else return GetInstance(0).GetTagAsInt("Columns"); } unsigned int Series::GetHeight() { Check3DImage(); if (GetInstanceCount() == 0) return 0; else return GetInstance(0).GetTagAsInt("Rows"); } void Series::LoadVoxelSize() { if (isVoxelSizeRead_) { return; } Check3DImage(); if (GetInstanceCount() == 0) { // Empty image, use some default value voxelSizeX_ = 1; voxelSizeY_ = 1; voxelSizeZ_ = 1; } else { try { std::string s = GetInstance(0).GetTagAsString("PixelSpacing"); size_t pos = s.find('\\'); assert(pos != std::string::npos); std::string sy = s.substr(0, pos); std::string sx = s.substr(pos + 1); voxelSizeX_ = boost::lexical_cast(sx); voxelSizeY_ = boost::lexical_cast(sy); voxelSizeZ_ = GetInstance(0).GetTagAsFloat("SliceThickness"); } catch (boost::bad_lexical_cast) { throw OrthancClientException(Orthanc::ErrorCode_NotImplemented); } } isVoxelSizeRead_ = true; } const char* Series::GetMainDicomTag(const char* tag, const char* defaultValue) const { if (series_["MainDicomTags"].isMember(tag)) { return series_["MainDicomTags"][tag].asCString(); } else { return defaultValue; } } void Series::Load3DImageInternal(void* target, Orthanc::PixelFormat format, size_t lineStride, size_t stackStride, Orthanc::ThreadedCommandProcessor::IListener* listener) { using namespace Orthanc; // Choose the extraction mode, depending on the format of the // target image. uint8_t bytesPerPixel; ImageExtractionMode mode; switch (format) { case PixelFormat_RGB24: bytesPerPixel = 3; mode = ImageExtractionMode_Preview; break; case PixelFormat_Grayscale8: bytesPerPixel = 1; mode = ImageExtractionMode_UInt8; // Preview ??? break; case PixelFormat_Grayscale16: bytesPerPixel = 2; mode = ImageExtractionMode_UInt16; break; case PixelFormat_SignedGrayscale16: bytesPerPixel = 2; mode = ImageExtractionMode_UInt16; format = PixelFormat_Grayscale16; break; default: throw OrthancClientException(ErrorCode_NotImplemented); } // Check that the target image is properly sized unsigned int sx = GetWidth(); unsigned int sy = GetHeight(); if (lineStride < sx * bytesPerPixel || stackStride < sx * sy * bytesPerPixel) { throw OrthancClientException(ErrorCode_BadRequest); } if (sx == 0 || sy == 0 || GetInstanceCount() == 0) { // Empty image, nothing to do if (listener) listener->SignalSuccess(0); return; } /** * Order the stacks according to their distance along the slice * normal (using the "Image Position Patient" tag). This works * even if the "SliceLocation" tag is absent. **/ SliceLocator locator(GetInstance(0)); typedef std::map Instances; Instances instances; for (unsigned int i = 0; i < GetInstanceCount(); i++) { float dist = locator.ComputeSliceLocation(GetInstance(i)); instances[dist] = &GetInstance(i); } if (instances.size() != GetInstanceCount()) { // Several instances have the same Z coordinate throw OrthancClientException(ErrorCode_NotImplemented); } // Submit the download of each stack as a set of commands ThreadedCommandProcessor processor(connection_.GetThreadCount()); if (listener != NULL) { processor.SetListener(*listener); } uint8_t* stackTarget = reinterpret_cast(target); for (Instances::iterator it = instances.begin(); it != instances.end(); ++it) { processor.Post(new ImageDownloadCommand(*it->second, format, mode, stackTarget, lineStride)); stackTarget += stackStride; } // Wait for all the stacks to be downloaded if (!processor.Join()) { throw OrthancClientException(ErrorCode_NetworkProtocol); } } float Series::GetVoxelSizeX() { LoadVoxelSize(); return voxelSizeX_; } float Series::GetVoxelSizeY() { LoadVoxelSize(); return voxelSizeY_; } float Series::GetVoxelSizeZ() { LoadVoxelSize(); return voxelSizeZ_; } void Series::Load3DImage(void* target, Orthanc::PixelFormat format, int64_t lineStride, int64_t stackStride, float* progress) { ProgressToFloatListener listener(progress); Load3DImageInternal(target, format, static_cast(lineStride), static_cast(stackStride), &listener); } } Orthanc-0.7.2/OrthancCppClient/Series.h0000644000000000000000000002161712237177136016067 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Instance.h" #include "../Core/MultiThreading/ArrayFilledByThreads.h" #include "../Core/MultiThreading/ThreadedCommandProcessor.h" namespace OrthancClient { /** * {summary}{Connection to a series stored in %Orthanc.} * {description}{This class encapsulates a connection to a series * from a remote instance of %Orthanc.} **/ class LAAW_API Series : public Orthanc::IDynamicObject, private Orthanc::ArrayFilledByThreads::IFiller { private: enum Status3DImage { Status3DImage_NotTested, Status3DImage_True, Status3DImage_False }; const OrthancConnection& connection_; std::string id_, url_; Json::Value series_; Orthanc::ArrayFilledByThreads instances_; Status3DImage status_; bool isVoxelSizeRead_; float voxelSizeX_; float voxelSizeY_; float voxelSizeZ_; void Check3DImage(); bool Is3DImageInternal(); void ReadSeries(); virtual size_t GetFillerSize() { return series_["Instances"].size(); } virtual Orthanc::IDynamicObject* GetFillerItem(size_t index); void Load3DImageInternal(void* target, Orthanc::PixelFormat format, size_t lineStride, size_t stackStride, Orthanc::ThreadedCommandProcessor::IListener* listener); void LoadVoxelSize(); public: /** * {summary}{Create a connection to some series.} * {param}{connection The remote instance of %Orthanc.} * {param}{id The %Orthanc identifier of the series.} **/ Series(const OrthancConnection& connection, const char* id); /** * {summary}{Reload the instances of this series.} * {description}{This method will reload the list of the instances of this series. Pay attention to the fact that the instances that have been previously returned by GetInstance() will be invalidated.} **/ void Reload() { instances_.Reload(); } /** * {summary}{Return the number of instances for this series.} * {returns}{The number of instances.} **/ uint32_t GetInstanceCount(); /** * {summary}{Get some instance of this series.} * {description}{This method will return an object that contains information about some instance. The instances are indexed by a number between 0 (inclusive) and the result of GetInstanceCount() (exclusive).} * {param}{index The index of the instance of interest.} * {returns}{The instance.} **/ Instance& GetInstance(uint32_t index); /** * {summary}{Get the %Orthanc identifier of this series.} * {returns}{The identifier.} **/ const char* GetId() const { return id_.c_str(); } /** * {summary}{Returns the URL to this series.} * {returns}{The URL.} **/ const char* GetUrl() const { return url_.c_str(); } /** * {summary}{Get the value of one of the main DICOM tags for this series.} * {param}{tag The name of the tag of interest ("Modality", "Manufacturer", "SeriesDate", "SeriesDescription", "SeriesInstanceUID"...).} * {param}{defaultValue The default value to be returned if this tag does not exist.} * {returns}{The value of the tag.} **/ const char* GetMainDicomTag(const char* tag, const char* defaultValue) const; /** * {summary}{Test whether this series encodes a 3D image that can be downloaded from %Orthanc.} * {returns}{"true" if and only if this is a 3D image.} **/ bool Is3DImage(); /** * {summary}{Get the width of the 3D image.} * {description}{Get the width of the 3D image (i.e. along the X-axis). This call is only valid if this series corresponds to a 3D image.} * {returns}{The width.} **/ uint32_t GetWidth(); /** * {summary}{Get the height of the 3D image.} * {description}{Get the height of the 3D image (i.e. along the Y-axis). This call is only valid if this series corresponds to a 3D image.} * {returns}{The height.} **/ uint32_t GetHeight(); /** * {summary}{Get the physical size of a voxel along the X-axis.} * {description}{Get the physical size of a voxel along the X-axis. This call is only valid if this series corresponds to a 3D image.} * {returns}{The voxel size.} **/ float GetVoxelSizeX(); /** * {summary}{Get the physical size of a voxel along the Y-axis.} * {description}{Get the physical size of a voxel along the Y-axis. This call is only valid if this series corresponds to a 3D image.} * {returns}{The voxel size.} **/ float GetVoxelSizeY(); /** * {summary}{Get the physical size of a voxel along the Z-axis.} * {description}{Get the physical size of a voxel along the Z-axis. This call is only valid if this series corresponds to a 3D image.} * {returns}{The voxel size.} **/ float GetVoxelSizeZ(); LAAW_API_INTERNAL void Load3DImage(void* target, Orthanc::PixelFormat format, int64_t lineStride, int64_t stackStride, Orthanc::ThreadedCommandProcessor::IListener& listener) { Load3DImageInternal(target, format, static_cast(lineStride), static_cast(stackStride), &listener); } /** * {summary}{Load the 3D image into a memory buffer.} * {description}{Load the 3D image into a memory buffer. This call is only valid if this series corresponds to a 3D image. The "target" buffer must be wide enough to store all the voxels of the image.} * {param}{target The target memory buffer.} * {param}{format The memory layout of the voxels.} * {param}{lineStride The number of bytes between two lines in the target memory buffer.} * {param}{stackStride The number of bytes between two 2D slices in the target memory buffer.} **/ void Load3DImage(void* target, Orthanc::PixelFormat format, int64_t lineStride, int64_t stackStride) { Load3DImageInternal(target, format, static_cast(lineStride), static_cast(stackStride), NULL); } /** * {summary}{Load the 3D image into a memory buffer.} * {description}{Load the 3D image into a memory buffer. This call is only valid if this series corresponds to a 3D image. The "target" buffer must be wide enough to store all the voxels of the image. This method will also update a progress indicator to monitor the loading of the image.} * {param}{target The target memory buffer.} * {param}{format The memory layout of the voxels.} * {param}{lineStride The number of bytes between two lines in the target memory buffer.} * {param}{stackStride The number of bytes between two 2D slices in the target memory buffer.} * {param}{progress A pointer to a floating-point number that is continuously updated by the download threads to reflect the percentage of completion (between 0 and 1). This value can be read from a separate thread.} **/ void Load3DImage(void* target, Orthanc::PixelFormat format, int64_t lineStride, int64_t stackStride, float* progress); }; } Orthanc-0.7.2/OrthancCppClient/SharedLibrary/AUTOGENERATED/ExternC.cpp0000644000000000000000000012214112237177136023254 0ustar 00000000000000/** * Laaw - Lightweight, Automated API Wrapper * Copyright (C) 2010-2013 Jomago - Alain Mazy, Benjamin Golinvaux, * Sebastien Jodogne * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ #include #include // For strcpy() and strlen() #include // For free() static char* LAAW_EXTERNC_CopyString(const char* str) { char* copy = reinterpret_cast(malloc(strlen(str) + 1)); strcpy(copy, str); return copy; } extern "C" { LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_1f1acb322ea4d0aad65172824607673c(void** newObject, const char* arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif *newObject = new OrthancClient::OrthancConnection(reinterpret_cast< const char* >(arg0)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_f3fd272e4636f6a531aabb72ee01cd5b(void** newObject, const char* arg0, const char* arg1, const char* arg2) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif *newObject = new OrthancClient::OrthancConnection(reinterpret_cast< const char* >(arg0), reinterpret_cast< const char* >(arg1), reinterpret_cast< const char* >(arg2)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_12d3de0a96e9efb11136a9811bb9ed38(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif delete static_cast(thisObject); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_557aee7b61817292a0f31269d3c35db7(const void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::OrthancConnection* this_ = static_cast(thisObject); *result = this_->GetThreadCount(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_0b8dff0ce67f10954a49b059e348837e(void* thisObject, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); this_->SetThreadCount(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_e05097c153f676e5a5ee54dcfc78256f(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); this_->Reload(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_e840242bf58d17d3c1d722da09ce88e0(const void* thisObject, const char** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::OrthancConnection* this_ = static_cast(thisObject); *result = this_->GetOrthancUrl(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_c9af31433001b5dfc012a552dc6d0050(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); *result = this_->GetPatientCount(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_3fba4d6b818180a44cd1cae6046334dc(void* thisObject, void** result, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); *result = &this_->GetPatient(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_aeb20dc75b9246188db857317e5e0ce7(void* thisObject, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); this_->DeletePatient(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_62689803d9871e4d9c51a648640b320b(void* thisObject, const char* arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); this_->StoreFile(reinterpret_cast< const char* >(arg0)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_2fb64c9e5a67eccd413b0e913469a421(void* thisObject, const void* arg0, uint64_t arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::OrthancConnection* this_ = static_cast(thisObject); this_->Store(reinterpret_cast< const void* >(arg0), arg1); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_6cf0d7268667f9b0aa4511bacf184919(void** newObject, void* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif *newObject = new OrthancClient::Patient(*reinterpret_cast< ::OrthancClient::OrthancConnection* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_7d81cd502ee27e859735d0ea7112b5a1(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif delete static_cast(thisObject); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_f756172daf04516eec3a566adabb4335(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Patient* this_ = static_cast(thisObject); this_->Reload(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_ddb68763ec902a97d579666a73a20118(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Patient* this_ = static_cast(thisObject); *result = this_->GetStudyCount(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_fba3c68b4be7558dbc65f7ce1ab57d63(void* thisObject, void** result, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Patient* this_ = static_cast(thisObject); *result = &this_->GetStudy(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_b4ca99d958f843493e58d1ef967340e1(const void* thisObject, const char** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Patient* this_ = static_cast(thisObject); *result = this_->GetId(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_78d5cc76d282437b6f93ec3b82c35701(const void* thisObject, const char** result, const char* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Patient* this_ = static_cast(thisObject); *result = this_->GetMainDicomTag(reinterpret_cast< const char* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_193599b9e345384fcdfcd47c29c55342(void** newObject, void* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif *newObject = new OrthancClient::Series(*reinterpret_cast< ::OrthancClient::OrthancConnection* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_7c97f17063a357d38c5fab1136ad12a0(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif delete static_cast(thisObject); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_48a2a1a9d68c047e22bfba23014643d2(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); this_->Reload(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_852bf8296ca21c5fde5ec565cc10721d(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetInstanceCount(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_efd04574e0779faa83df1f2d8f9888db(void* thisObject, void** result, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = &this_->GetInstance(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_736247ff5e8036dac38163da6f666ed5(const void* thisObject, const char** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetId(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_d82d2598a7a73f4b6fcc0c09c25b08ca(const void* thisObject, const char** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetUrl(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_88134b978f9acb2aecdadf54aeab3c64(const void* thisObject, const char** result, const char* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetMainDicomTag(reinterpret_cast< const char* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_152cb1b704c053d24b0dab7461ba6ea3(void* thisObject, int32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->Is3DImage(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_eee03f337ec81d9f1783cd41e5238757(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetWidth(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_006f08237bd7611636fc721baebfb4c5(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetHeight(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_b794f5cd3dad7d7b575dd1fd902afdd0(void* thisObject, float* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetVoxelSizeX(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_8ee2e50dd9df8f66a3c1766090dd03ab(void* thisObject, float* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetVoxelSizeY(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_046aed35bbe4751691f4c34cc249a61d(void* thisObject, float* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); *result = this_->GetVoxelSizeZ(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_4dcc7a0fd025efba251ac6e9b701c2c5(void* thisObject, void* arg0, int32_t arg1, int64_t arg2, int64_t arg3) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); this_->Load3DImage(reinterpret_cast< void* >(arg0), static_cast< ::Orthanc::PixelFormat >(arg1), arg2, arg3); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_b2601a161c24ad0a1d3586246f87452c(void* thisObject, void* arg0, int32_t arg1, int64_t arg2, int64_t arg3, float* arg4) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Series* this_ = static_cast(thisObject); this_->Load3DImage(reinterpret_cast< void* >(arg0), static_cast< ::Orthanc::PixelFormat >(arg1), arg2, arg3, reinterpret_cast< float* >(arg4)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_b01c6003238eb46c8db5dc823d7ca678(void** newObject, void* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif *newObject = new OrthancClient::Study(*reinterpret_cast< ::OrthancClient::OrthancConnection* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_0147007fb99bad8cd95a139ec8795376(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif delete static_cast(thisObject); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_e65b20b7e0170b67544cd6664a4639b7(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Study* this_ = static_cast(thisObject); this_->Reload(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_470e981b0e41f17231ba0ae6f3033321(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Study* this_ = static_cast(thisObject); *result = this_->GetSeriesCount(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_04cefd138b6ea15ad909858f2a0a8f05(void* thisObject, void** result, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Study* this_ = static_cast(thisObject); *result = &this_->GetSeries(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_aee5b1f6f0c082f2c3b0986f9f6a18c7(const void* thisObject, const char** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Study* this_ = static_cast(thisObject); *result = this_->GetId(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_93965682bace75491413e1f0b8d5a654(const void* thisObject, const char** result, const char* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Study* this_ = static_cast(thisObject); *result = this_->GetMainDicomTag(reinterpret_cast< const char* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_6c5ad02f91b583e29cebd0bd319ce21d(void** newObject, void* arg0, const char* arg1) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif *newObject = new OrthancClient::Instance(*reinterpret_cast< ::OrthancClient::OrthancConnection* >(arg0), reinterpret_cast< const char* >(arg1)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_4068241c44a9c1367fe0e57be523f207(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif delete static_cast(thisObject); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_236ee8b403bc99535a8a4695c0cd45cb(const void* thisObject, const char** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetId(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_2a437b7aba6bb01e81113835be8f0146(void* thisObject, int32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); this_->SetImageExtractionMode(static_cast< ::Orthanc::ImageExtractionMode >(arg0)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_2bcbcb850934ae0bb4c6f0cc940e6cda(const void* thisObject, int32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetImageExtractionMode(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_8d415c3a78a48e7e61d9fd24e7c79484(const void* thisObject, const char** result, const char* arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetTagAsString(reinterpret_cast< const char* >(arg0)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_70d2f8398bbc63b5f792b69b4ad5fecb(const void* thisObject, float* result, const char* arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetTagAsFloat(reinterpret_cast< const char* >(arg0)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_1729a067d902771517388eedd7346b23(const void* thisObject, int32_t* result, const char* arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif const OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetTagAsInt(reinterpret_cast< const char* >(arg0)); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_72e2aeee66cd3abd8ab7e987321c3745(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetWidth(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_1ea3df5a1ac1a1a687fe7325adddb6f0(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetHeight(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_99b4f370e4f532d8b763e2cb49db92f8(void* thisObject, uint32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetPitch(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_c41c742b68617f1c0590577a0a5ebc0c(void* thisObject, int32_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetPixelFormat(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_142dd2feba0fc1d262bbd0baeb441a8b(void* thisObject, const void** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetBuffer(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_5f5c9f81a4dff8daa6c359f1d0488fef(void* thisObject, const void** result, uint32_t arg0) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetBuffer(arg0); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_9ca979fffd08fa256306d4e68d8b0e91(void* thisObject, uint64_t* result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetDicomSize(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_6f2d77a26edc91c28d89408dbc3c271e(void* thisObject, const void** result) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); *result = this_->GetDicom(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_c0f494b80d4ff8b232df7a75baa0700a(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); this_->DiscardImage(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API char* LAAW_CALL_CONVENTION LAAW_EXTERNC_d604f44bd5195e082e745e9cbc164f4c(void* thisObject) { try { #ifdef LAAW_EXTERNC_START_FUNCTION LAAW_EXTERNC_START_FUNCTION; #endif OrthancClient::Instance* this_ = static_cast(thisObject); this_->DiscardDicom(); return NULL; } catch (::Laaw::LaawException& e) { return LAAW_EXTERNC_CopyString(e.What()); } catch (...) { return LAAW_EXTERNC_CopyString("..."); } } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetDescription() { return "Native client to the REST API of Orthanc"; } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetCompany() { return "CHU of Liege"; } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetProduct() { return "OrthancClient"; } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetCopyright() { return "(c) 2012-2013, Sebastien Jodogne, CHU of Liege"; } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetVersion() { return "0.7"; } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetFileVersion() { return "0.7.0.2"; } LAAW_EXPORT_DLL_API const char* LAAW_CALL_CONVENTION LAAW_EXTERNC_GetFullVersion() { return "0.7.2"; } LAAW_EXPORT_DLL_API void LAAW_CALL_CONVENTION LAAW_EXTERNC_FreeString(char* str) { if (str != NULL) free(str); } } Orthanc-0.7.2/OrthancCppClient/SharedLibrary/AUTOGENERATED/OrthancCppClient.h0000644000000000000000000020747212237177136024564 0ustar 00000000000000/** * Laaw - Lightweight, Automated API Wrapper * Copyright (C) 2010-2013 Jomago - Alain Mazy, Benjamin Golinvaux, * Sebastien Jodogne * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ /** * @file **/ #pragma once #include #include #include #include #if defined(_WIN32) /******************************************************************** ** This is the Windows-specific section ********************************************************************/ #include /* cf. http://sourceforge.net/p/predef/wiki/Architectures/ */ #ifdef _M_X64 /* 64 bits target */ #define LAAW_ORTHANC_CLIENT_CALL_CONV __fastcall #define LAAW_ORTHANC_CLIENT_CALL_DECORATION(Name, StdCallSuffix) Name #define LAAW_ORTHANC_CLIENT_DEFAULT_PATH "OrthancClient_Windows64.dll" #else /* 32 bits target */ #define LAAW_ORTHANC_CLIENT_CALL_CONV __stdcall #define LAAW_ORTHANC_CLIENT_CALL_DECORATION(Name, StdCallSuffix) "_" Name "@" StdCallSuffix #define LAAW_ORTHANC_CLIENT_DEFAULT_PATH "OrthancClient_Windows32.dll" #endif #define LAAW_ORTHANC_CLIENT_HANDLE_TYPE HINSTANCE #define LAAW_ORTHANC_CLIENT_HANDLE_NULL 0 #define LAAW_ORTHANC_CLIENT_FUNCTION_TYPE FARPROC #define LAAW_ORTHANC_CLIENT_LOADER(path) LoadLibraryA(path) #define LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle, name, decoration) GetProcAddress(handle, LAAW_ORTHANC_CLIENT_CALL_DECORATION(name, decoration)) #define LAAW_ORTHANC_CLIENT_CLOSER(handle) FreeLibrary(handle) /******************************************************************** ** This is the Linux-specific section ********************************************************************/ #elif defined (__linux) #include #include /* cf. http://sourceforge.net/p/predef/wiki/Architectures/ */ #ifdef __amd64__ #define LAAW_ORTHANC_CLIENT_DEFAULT_PATH "libOrthancClient.so.0.7" #else #define LAAW_ORTHANC_CLIENT_DEFAULT_PATH "libOrthancClient.so.0.7" #endif #define LAAW_ORTHANC_CLIENT_CALL_CONV #define LAAW_ORTHANC_CLIENT_HANDLE_TYPE void* #define LAAW_ORTHANC_CLIENT_HANDLE_NULL NULL #define LAAW_ORTHANC_CLIENT_FUNCTION_TYPE intptr_t #define LAAW_ORTHANC_CLIENT_LOADER(path) dlopen(path, RTLD_LAZY) #define LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle, name, decoration) (LAAW_ORTHANC_CLIENT_FUNCTION_TYPE) dlsym(handle, name) #define LAAW_ORTHANC_CLIENT_CLOSER(handle) dlclose(handle) #else #error Please support your platform here #endif /******************************************************************** ** Definition of the integer types ********************************************************************/ #ifndef LAAW_INT8 // Only define the integer types once #if defined(__GNUC__) // Under GCC (including MinGW), the stdint.h standard header is used. #include #define LAAW_INT8 int8_t #define LAAW_UINT8 uint8_t #define LAAW_INT16 int16_t #define LAAW_UINT16 uint16_t #define LAAW_INT32 int32_t #define LAAW_UINT32 uint32_t #define LAAW_INT64 int64_t #define LAAW_UINT64 uint64_t #elif defined(_MSC_VER) // Under Visual Studio, it is required to define the various integer // types by hand. #if (_MSC_VER < 1300) typedef signed char LAAW_INT8; typedef signed short LAAW_INT16; typedef signed int LAAW_INT32; typedef unsigned char LAAW_UINT8; typedef unsigned short LAAW_UINT16; typedef unsigned int LAAW_UINT32; #else typedef signed __int8 LAAW_INT8; typedef signed __int16 LAAW_INT16; typedef signed __int32 LAAW_INT32; typedef unsigned __int8 LAAW_UINT8; typedef unsigned __int16 LAAW_UINT16; typedef unsigned __int32 LAAW_UINT32; #endif typedef signed __int64 LAAW_INT64; typedef unsigned __int64 LAAW_UINT64; #else #error "Please support your compiler here" #endif #endif /******************************************************************** ** This is a shared section between Windows and Linux ********************************************************************/ namespace OrthancClient { /** * @brief Exception class that is thrown by the functions of this shared library. **/ class OrthancClientException : public std::exception { private: std::string message_; public: /** * @brief Constructs an exception. * @param message The error message. **/ OrthancClientException(std::string message) : message_(message) { } ~OrthancClientException() throw() { } /** * @brief Get the error message associated with this exception. * @returns The error message. **/ const std::string& What() const throw() { return message_; } }; } namespace OrthancClient { namespace Internals { /** * This internal class implements a Singleton design pattern that will * store a reference to the shared library handle, together with a * pointer to each function in the shared library. **/ class Library { private: LAAW_ORTHANC_CLIENT_HANDLE_TYPE handle_; LAAW_ORTHANC_CLIENT_FUNCTION_TYPE functionsIndex_[60 + 1]; void Load(const char* sharedLibraryPath) { if (handle_ != LAAW_ORTHANC_CLIENT_HANDLE_NULL) { // Do nothing if the library is already loaded return; } /* Setup the path to the default shared library if not provided */ if (sharedLibraryPath == NULL) { sharedLibraryPath = LAAW_ORTHANC_CLIENT_DEFAULT_PATH; } /* Load the shared library */ handle_ = LAAW_ORTHANC_CLIENT_LOADER(sharedLibraryPath); if (handle_ == LAAW_ORTHANC_CLIENT_HANDLE_NULL) { throw ::OrthancClient::OrthancClientException("Error loading shared library"); } LoadFunctions(); } inline void LoadFunctions(); void FreeString(char* str) { typedef void (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (char*); Function function = (Function) GetFunction(60); function(str); } Library() { handle_ = LAAW_ORTHANC_CLIENT_HANDLE_NULL; } ~Library() { Finalize(); } public: LAAW_ORTHANC_CLIENT_FUNCTION_TYPE GetFunction(unsigned int index) { /** * If the library has not been manually initialized by a call to * ::OrthancClient::Initialize(), it is loaded from * the default location (lazy initialization). **/ if (handle_ == NULL) { Load(NULL); } return functionsIndex_[index]; } void ThrowExceptionIfNeeded(char* message) { if (message != NULL) { std::string tmp(message); FreeString(message); throw ::OrthancClient::OrthancClientException(tmp); } } static inline Library& GetInstance() { /** * This function defines a "static variable" inside a "static * inline method" of a class. This ensures that a single * instance of this variable will be used across all the * compilation modules of the software. * http://stackoverflow.com/a/1389403/881731 **/ static Library singleton; return singleton; } static void Initialize(const char* sharedLibraryPath) { GetInstance().Load(sharedLibraryPath); } void Finalize() { if (handle_ != LAAW_ORTHANC_CLIENT_HANDLE_NULL) { LAAW_ORTHANC_CLIENT_CLOSER(handle_); handle_ = LAAW_ORTHANC_CLIENT_HANDLE_NULL; } } }; }} /*! * \addtogroup Global Global definitions. * @{ * @} */ namespace OrthancClient { /*! * \addtogroup Initialization Initialization of the shared library. * @{ */ /** * @brief Manually initialize the shared library, using the default library name. * * Call this method before using the library to ensure correct * behaviour in multi-threaded applications. This method is also * useful to control the time at which the shared library is * loaded (e.g. for real-time applications). **/ inline void Initialize() { ::OrthancClient::Internals::Library::Initialize(NULL); } /** * @brief Manually initialize the shared library. * * Call this method before using the library to ensure correct * behaviour in multi-threaded applications. This method is also * useful to control the time at which the shared library is * loaded (e.g. for real-time applications). * * @param sharedLibraryPath The path to the shared library that * contains the module. **/ inline void Initialize(const std::string& sharedLibraryPath) { ::OrthancClient::Internals::Library::Initialize(sharedLibraryPath.c_str()); } /** * @brief Manually finalize the shared library. * * Calling explicitly this function is not mandatory. It is useful to * force the release of the resources acquired by the shared library, * or to manually control the order in which the global variables get * deleted. **/ inline void Finalize() { ::OrthancClient::Internals::Library::GetInstance().Finalize(); } /** * @} */ } namespace OrthancClient { namespace Internals { inline void Library::LoadFunctions() { typedef const char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (); Function getVersion = (Function) LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_GetVersion", "0"); if (getVersion == NULL) { throw ::OrthancClient::OrthancClientException("Unable to get the library version"); } /** * It is assumed that the API does not change when the revision * number (MAJOR.MINOR.REVISION) changes. **/ if (strcmp(getVersion(), "0.7")) { throw ::OrthancClient::OrthancClientException("Mismatch between the C++ header and the library version"); } functionsIndex_[60] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_FreeString", "4"); functionsIndex_[3] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_557aee7b61817292a0f31269d3c35db7", "8"); functionsIndex_[4] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_0b8dff0ce67f10954a49b059e348837e", "8"); functionsIndex_[5] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_e05097c153f676e5a5ee54dcfc78256f", "4"); functionsIndex_[6] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_e840242bf58d17d3c1d722da09ce88e0", "8"); functionsIndex_[7] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_c9af31433001b5dfc012a552dc6d0050", "8"); functionsIndex_[8] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_3fba4d6b818180a44cd1cae6046334dc", "12"); functionsIndex_[9] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_aeb20dc75b9246188db857317e5e0ce7", "8"); functionsIndex_[10] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_62689803d9871e4d9c51a648640b320b", "8"); functionsIndex_[11] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_2fb64c9e5a67eccd413b0e913469a421", "16"); functionsIndex_[0] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_1f1acb322ea4d0aad65172824607673c", "8"); functionsIndex_[1] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_f3fd272e4636f6a531aabb72ee01cd5b", "16"); functionsIndex_[2] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_12d3de0a96e9efb11136a9811bb9ed38", "4"); functionsIndex_[14] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_f756172daf04516eec3a566adabb4335", "4"); functionsIndex_[15] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_ddb68763ec902a97d579666a73a20118", "8"); functionsIndex_[16] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_fba3c68b4be7558dbc65f7ce1ab57d63", "12"); functionsIndex_[17] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_b4ca99d958f843493e58d1ef967340e1", "8"); functionsIndex_[18] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_78d5cc76d282437b6f93ec3b82c35701", "16"); functionsIndex_[12] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_6cf0d7268667f9b0aa4511bacf184919", "12"); functionsIndex_[13] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_7d81cd502ee27e859735d0ea7112b5a1", "4"); functionsIndex_[21] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_48a2a1a9d68c047e22bfba23014643d2", "4"); functionsIndex_[22] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_852bf8296ca21c5fde5ec565cc10721d", "8"); functionsIndex_[23] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_efd04574e0779faa83df1f2d8f9888db", "12"); functionsIndex_[24] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_736247ff5e8036dac38163da6f666ed5", "8"); functionsIndex_[25] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_d82d2598a7a73f4b6fcc0c09c25b08ca", "8"); functionsIndex_[26] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_88134b978f9acb2aecdadf54aeab3c64", "16"); functionsIndex_[27] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_152cb1b704c053d24b0dab7461ba6ea3", "8"); functionsIndex_[28] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_eee03f337ec81d9f1783cd41e5238757", "8"); functionsIndex_[29] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_006f08237bd7611636fc721baebfb4c5", "8"); functionsIndex_[30] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_b794f5cd3dad7d7b575dd1fd902afdd0", "8"); functionsIndex_[31] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_8ee2e50dd9df8f66a3c1766090dd03ab", "8"); functionsIndex_[32] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_046aed35bbe4751691f4c34cc249a61d", "8"); functionsIndex_[33] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_4dcc7a0fd025efba251ac6e9b701c2c5", "28"); functionsIndex_[34] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_b2601a161c24ad0a1d3586246f87452c", "32"); functionsIndex_[19] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_193599b9e345384fcdfcd47c29c55342", "12"); functionsIndex_[20] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_7c97f17063a357d38c5fab1136ad12a0", "4"); functionsIndex_[37] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_e65b20b7e0170b67544cd6664a4639b7", "4"); functionsIndex_[38] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_470e981b0e41f17231ba0ae6f3033321", "8"); functionsIndex_[39] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_04cefd138b6ea15ad909858f2a0a8f05", "12"); functionsIndex_[40] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_aee5b1f6f0c082f2c3b0986f9f6a18c7", "8"); functionsIndex_[41] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_93965682bace75491413e1f0b8d5a654", "16"); functionsIndex_[35] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_b01c6003238eb46c8db5dc823d7ca678", "12"); functionsIndex_[36] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_0147007fb99bad8cd95a139ec8795376", "4"); functionsIndex_[44] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_236ee8b403bc99535a8a4695c0cd45cb", "8"); functionsIndex_[45] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_2a437b7aba6bb01e81113835be8f0146", "8"); functionsIndex_[46] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_2bcbcb850934ae0bb4c6f0cc940e6cda", "8"); functionsIndex_[47] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_8d415c3a78a48e7e61d9fd24e7c79484", "12"); functionsIndex_[48] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_70d2f8398bbc63b5f792b69b4ad5fecb", "12"); functionsIndex_[49] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_1729a067d902771517388eedd7346b23", "12"); functionsIndex_[50] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_72e2aeee66cd3abd8ab7e987321c3745", "8"); functionsIndex_[51] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_1ea3df5a1ac1a1a687fe7325adddb6f0", "8"); functionsIndex_[52] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_99b4f370e4f532d8b763e2cb49db92f8", "8"); functionsIndex_[53] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_c41c742b68617f1c0590577a0a5ebc0c", "8"); functionsIndex_[54] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_142dd2feba0fc1d262bbd0baeb441a8b", "8"); functionsIndex_[55] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_5f5c9f81a4dff8daa6c359f1d0488fef", "12"); functionsIndex_[56] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_9ca979fffd08fa256306d4e68d8b0e91", "8"); functionsIndex_[57] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_6f2d77a26edc91c28d89408dbc3c271e", "8"); functionsIndex_[58] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_c0f494b80d4ff8b232df7a75baa0700a", "4"); functionsIndex_[59] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_d604f44bd5195e082e745e9cbc164f4c", "4"); functionsIndex_[42] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_6c5ad02f91b583e29cebd0bd319ce21d", "12"); functionsIndex_[43] = LAAW_ORTHANC_CLIENT_GET_FUNCTION(handle_, "LAAW_EXTERNC_4068241c44a9c1367fe0e57be523f207", "4"); /* Check whether the functions were properly loaded */ for (unsigned int i = 0; i <= 60; i++) { if (functionsIndex_[i] == (LAAW_ORTHANC_CLIENT_FUNCTION_TYPE) NULL) { throw ::OrthancClient::OrthancClientException("Unable to load the functions of the shared library"); } } } }} namespace OrthancClient { class OrthancConnection; } namespace OrthancClient { class Patient; } namespace OrthancClient { class Series; } namespace OrthancClient { class Study; } namespace OrthancClient { class Instance; } namespace Orthanc { /** * @brief The memory layout of the pixels (resp. voxels) of a 2D (resp. 3D) image. * * The memory layout of the pixels (resp. voxels) of a 2D (resp. 3D) image. * * @ingroup Global **/ enum PixelFormat { /** * @brief Graylevel, signed 16bpp image. * * The image is graylevel. Each pixel is signed and stored in two bytes. * **/ PixelFormat_SignedGrayscale16 = 3, /** * @brief Color image in RGB24 format. * * Color image in RGB24 format. * **/ PixelFormat_RGB24 = 0, /** * @brief Graylevel 8bpp image. * * The image is graylevel. Each pixel is unsigned and stored in one byte. * **/ PixelFormat_Grayscale8 = 1, /** * @brief Graylevel, unsigned 16bpp image. * * The image is graylevel. Each pixel is unsigned and stored in two bytes. * **/ PixelFormat_Grayscale16 = 2 }; } namespace Orthanc { /** * @brief The extraction mode specifies the way the values of the pixels are scaled when downloading a 2D image. * * The extraction mode specifies the way the values of the pixels are scaled when downloading a 2D image. * * @ingroup Global **/ enum ImageExtractionMode { /** * @brief Truncation to the [-32768, 32767] range. * * Truncation to the [-32768, 32767] range. * **/ ImageExtractionMode_Int16 = 3, /** * @brief Rescaled to 8bpp. * * The minimum value of the image is set to 0, and its maximum value is set to 255. * **/ ImageExtractionMode_Preview = 0, /** * @brief Truncation to the [0, 255] range. * * Truncation to the [0, 255] range. * **/ ImageExtractionMode_UInt8 = 1, /** * @brief Truncation to the [0, 65535] range. * * Truncation to the [0, 65535] range. * **/ ImageExtractionMode_UInt16 = 2 }; } namespace OrthancClient { /** * @brief Connection to an instance of %Orthanc. * * This class encapsulates a connection to a remote instance of %Orthanc through its REST API. * **/ class OrthancConnection { friend class ::OrthancClient::Patient; friend class ::OrthancClient::Series; friend class ::OrthancClient::Study; friend class ::OrthancClient::Instance; private: bool isReference_; OrthancConnection& operator= (const OrthancConnection&); // Assignment is forbidden void* pimpl_; OrthancConnection(void* pimpl) : isReference_(true), pimpl_(pimpl) {} public: /** * @brief Construct a new reference to this object. * * Construct a new reference to this object. Pay attention to the fact that when the referenced object is deleted, the content of this object will be invalid. * * @param other The original object. **/ OrthancConnection(const OrthancConnection& other) : isReference_(true), pimpl_(other.pimpl_) { } inline OrthancConnection(const ::std::string& orthancUrl); inline OrthancConnection(const ::std::string& orthancUrl, const ::std::string& username, const ::std::string& password); inline ~OrthancConnection(); inline LAAW_UINT32 GetThreadCount() const; inline void SetThreadCount(LAAW_UINT32 threadCount); inline void Reload(); inline ::std::string GetOrthancUrl() const; inline LAAW_UINT32 GetPatientCount(); inline ::OrthancClient::Patient GetPatient(LAAW_UINT32 index); inline void DeletePatient(LAAW_UINT32 index); inline void StoreFile(const ::std::string& filename); inline void Store(const void* dicom, LAAW_UINT64 size); }; } namespace OrthancClient { /** * @brief Connection to a patient stored in %Orthanc. * * This class encapsulates a connection to a patient from a remote instance of %Orthanc. * **/ class Patient { friend class ::OrthancClient::OrthancConnection; friend class ::OrthancClient::Series; friend class ::OrthancClient::Study; friend class ::OrthancClient::Instance; private: bool isReference_; Patient& operator= (const Patient&); // Assignment is forbidden void* pimpl_; Patient(void* pimpl) : isReference_(true), pimpl_(pimpl) {} public: /** * @brief Construct a new reference to this object. * * Construct a new reference to this object. Pay attention to the fact that when the referenced object is deleted, the content of this object will be invalid. * * @param other The original object. **/ Patient(const Patient& other) : isReference_(true), pimpl_(other.pimpl_) { } inline Patient(::OrthancClient::OrthancConnection& connection, const ::std::string& id); inline ~Patient(); inline void Reload(); inline LAAW_UINT32 GetStudyCount(); inline ::OrthancClient::Study GetStudy(LAAW_UINT32 index); inline ::std::string GetId() const; inline ::std::string GetMainDicomTag(const ::std::string& tag, const ::std::string& defaultValue) const; }; } namespace OrthancClient { /** * @brief Connection to a series stored in %Orthanc. * * This class encapsulates a connection to a series from a remote instance of %Orthanc. * **/ class Series { friend class ::OrthancClient::OrthancConnection; friend class ::OrthancClient::Patient; friend class ::OrthancClient::Study; friend class ::OrthancClient::Instance; private: bool isReference_; Series& operator= (const Series&); // Assignment is forbidden void* pimpl_; Series(void* pimpl) : isReference_(true), pimpl_(pimpl) {} public: /** * @brief Construct a new reference to this object. * * Construct a new reference to this object. Pay attention to the fact that when the referenced object is deleted, the content of this object will be invalid. * * @param other The original object. **/ Series(const Series& other) : isReference_(true), pimpl_(other.pimpl_) { } inline Series(::OrthancClient::OrthancConnection& connection, const ::std::string& id); inline ~Series(); inline void Reload(); inline LAAW_UINT32 GetInstanceCount(); inline ::OrthancClient::Instance GetInstance(LAAW_UINT32 index); inline ::std::string GetId() const; inline ::std::string GetUrl() const; inline ::std::string GetMainDicomTag(const ::std::string& tag, const ::std::string& defaultValue) const; inline bool Is3DImage(); inline LAAW_UINT32 GetWidth(); inline LAAW_UINT32 GetHeight(); inline float GetVoxelSizeX(); inline float GetVoxelSizeY(); inline float GetVoxelSizeZ(); inline void Load3DImage(void* target, ::Orthanc::PixelFormat format, LAAW_INT64 lineStride, LAAW_INT64 stackStride); inline void Load3DImage(void* target, ::Orthanc::PixelFormat format, LAAW_INT64 lineStride, LAAW_INT64 stackStride, float progress[]); }; } namespace OrthancClient { /** * @brief Connection to a study stored in %Orthanc. * * This class encapsulates a connection to a study from a remote instance of %Orthanc. * **/ class Study { friend class ::OrthancClient::OrthancConnection; friend class ::OrthancClient::Patient; friend class ::OrthancClient::Series; friend class ::OrthancClient::Instance; private: bool isReference_; Study& operator= (const Study&); // Assignment is forbidden void* pimpl_; Study(void* pimpl) : isReference_(true), pimpl_(pimpl) {} public: /** * @brief Construct a new reference to this object. * * Construct a new reference to this object. Pay attention to the fact that when the referenced object is deleted, the content of this object will be invalid. * * @param other The original object. **/ Study(const Study& other) : isReference_(true), pimpl_(other.pimpl_) { } inline Study(::OrthancClient::OrthancConnection& connection, const ::std::string& id); inline ~Study(); inline void Reload(); inline LAAW_UINT32 GetSeriesCount(); inline ::OrthancClient::Series GetSeries(LAAW_UINT32 index); inline ::std::string GetId() const; inline ::std::string GetMainDicomTag(const ::std::string& tag, const ::std::string& defaultValue) const; }; } namespace OrthancClient { /** * @brief Connection to an instance stored in %Orthanc. * * This class encapsulates a connection to an image instance from a remote instance of %Orthanc. * **/ class Instance { friend class ::OrthancClient::OrthancConnection; friend class ::OrthancClient::Patient; friend class ::OrthancClient::Series; friend class ::OrthancClient::Study; private: bool isReference_; Instance& operator= (const Instance&); // Assignment is forbidden void* pimpl_; Instance(void* pimpl) : isReference_(true), pimpl_(pimpl) {} public: /** * @brief Construct a new reference to this object. * * Construct a new reference to this object. Pay attention to the fact that when the referenced object is deleted, the content of this object will be invalid. * * @param other The original object. **/ Instance(const Instance& other) : isReference_(true), pimpl_(other.pimpl_) { } inline Instance(::OrthancClient::OrthancConnection& connection, const ::std::string& id); inline ~Instance(); inline ::std::string GetId() const; inline void SetImageExtractionMode(::Orthanc::ImageExtractionMode mode); inline ::Orthanc::ImageExtractionMode GetImageExtractionMode() const; inline ::std::string GetTagAsString(const ::std::string& tag) const; inline float GetTagAsFloat(const ::std::string& tag) const; inline LAAW_INT32 GetTagAsInt(const ::std::string& tag) const; inline LAAW_UINT32 GetWidth(); inline LAAW_UINT32 GetHeight(); inline LAAW_UINT32 GetPitch(); inline ::Orthanc::PixelFormat GetPixelFormat(); inline const void* GetBuffer(); inline const void* GetBuffer(LAAW_UINT32 y); inline LAAW_UINT64 GetDicomSize(); inline const void* GetDicom(); inline void DiscardImage(); inline void DiscardDicom(); }; } namespace OrthancClient { /** * @brief Create a connection to an instance of %Orthanc. * * Create a connection to an instance of %Orthanc. * * @param orthancUrl URL to which the REST API of %Orthanc is listening. **/ inline OrthancConnection::OrthancConnection(const ::std::string& orthancUrl) { isReference_ = false; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void**, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(0); char* error = function(&pimpl_, orthancUrl.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Create a connection to an instance of %Orthanc, with authentication. * * Create a connection to an instance of %Orthanc, with authentication. * * @param orthancUrl URL to which the REST API of %Orthanc is listening. * @param username The username. * @param password The password. **/ inline OrthancConnection::OrthancConnection(const ::std::string& orthancUrl, const ::std::string& username, const ::std::string& password) { isReference_ = false; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void**, const char*, const char*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(1); char* error = function(&pimpl_, orthancUrl.c_str(), username.c_str(), password.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Destructs the object. * * Destructs the object. * **/ inline OrthancConnection::~OrthancConnection() { if (isReference_) return; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(2); char* error = function(pimpl_); error = error; // Remove warning about unused variable } /** * @brief Returns the number of threads for this connection. * * Returns the number of simultaneous connections that are used when downloading information from this instance of %Orthanc. * * @return The number of threads. **/ inline LAAW_UINT32 OrthancConnection::GetThreadCount() const { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(3); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Sets the number of threads for this connection. * * Sets the number of simultaneous connections that are used when downloading information from this instance of %Orthanc. * * @param threadCount The number of threads. **/ inline void OrthancConnection::SetThreadCount(LAAW_UINT32 threadCount) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(4); char* error = function(pimpl_, threadCount); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Reload the list of the patients. * * This method will reload the list of the patients from the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated. * **/ inline void OrthancConnection::Reload() { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(5); char* error = function(pimpl_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Returns the URL of this instance of %Orthanc. * * Returns the URL of the remote %Orthanc instance to which this object is connected. * * @return The URL. **/ inline ::std::string OrthancConnection::GetOrthancUrl() const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(6); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Returns the number of patients. * * Returns the number of patients that are stored in the remote instance of %Orthanc. * * @return The number of patients. **/ inline LAAW_UINT32 OrthancConnection::GetPatientCount() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(7); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get some patient. * * This method will return an object that contains information about some patient. The patients are indexed by a number between 0 (inclusive) and the result of GetPatientCount() (exclusive). * * @param index The index of the patient of interest. * @return The patient. **/ inline ::OrthancClient::Patient OrthancConnection::GetPatient(LAAW_UINT32 index) { void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, void**, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(8); char* error = function(pimpl_, &result_, index); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return ::OrthancClient::Patient(result_); } /** * @brief Delete some patient. * * Delete some patient from the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated. * * @param index The index of the patient of interest. * @return The patient. **/ inline void OrthancConnection::DeletePatient(LAAW_UINT32 index) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(9); char* error = function(pimpl_, index); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Send a DICOM file. * * This method will store a DICOM file in the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated. * * @param filename Path to the DICOM file **/ inline void OrthancConnection::StoreFile(const ::std::string& filename) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(10); char* error = function(pimpl_, filename.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Send a DICOM file that is contained inside a memory buffer. * * This method will store a DICOM file in the remote instance of %Orthanc. Pay attention to the fact that the patients that have been previously returned by GetPatient() will be invalidated. * * @param dicom The memory buffer containing the DICOM file. * @param size The size of the DICOM file. **/ inline void OrthancConnection::Store(const void* dicom, LAAW_UINT64 size) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, const void*, LAAW_UINT64); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(11); char* error = function(pimpl_, dicom, size); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } } namespace OrthancClient { /** * @brief Create a connection to some patient. * * Create a connection to some patient. * * @param connection The remote instance of %Orthanc. * @param id The %Orthanc identifier of the patient. **/ inline Patient::Patient(::OrthancClient::OrthancConnection& connection, const ::std::string& id) { isReference_ = false; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void**, void*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(12); char* error = function(&pimpl_, connection.pimpl_, id.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Destructs the object. * * Destructs the object. * **/ inline Patient::~Patient() { if (isReference_) return; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(13); char* error = function(pimpl_); error = error; // Remove warning about unused variable } /** * @brief Reload the studies of this patient. * * This method will reload the list of the studies of this patient. Pay attention to the fact that the studies that have been previously returned by GetStudy() will be invalidated. * **/ inline void Patient::Reload() { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(14); char* error = function(pimpl_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Return the number of studies for this patient. * * Return the number of studies for this patient. * * @return The number of studies. **/ inline LAAW_UINT32 Patient::GetStudyCount() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(15); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get some study of this patient. * * This method will return an object that contains information about some study. The studies are indexed by a number between 0 (inclusive) and the result of GetStudyCount() (exclusive). * * @param index The index of the study of interest. * @return The study. **/ inline ::OrthancClient::Study Patient::GetStudy(LAAW_UINT32 index) { void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, void**, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(16); char* error = function(pimpl_, &result_, index); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return ::OrthancClient::Study(result_); } /** * @brief Get the %Orthanc identifier of this patient. * * Get the %Orthanc identifier of this patient. * * @return The identifier. **/ inline ::std::string Patient::GetId() const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(17); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Get the value of one of the main DICOM tags for this patient. * * Get the value of one of the main DICOM tags for this patient. * * @param tag The name of the tag of interest ("PatientName", "PatientID", "PatientSex" or "PatientBirthDate"). * @param defaultValue The default value to be returned if this tag does not exist. * @return The value of the tag. **/ inline ::std::string Patient::GetMainDicomTag(const ::std::string& tag, const ::std::string& defaultValue) const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**, const char*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(18); char* error = function(pimpl_, &result_, tag.c_str(), defaultValue.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } } namespace OrthancClient { /** * @brief Create a connection to some series. * * Create a connection to some series. * * @param connection The remote instance of %Orthanc. * @param id The %Orthanc identifier of the series. **/ inline Series::Series(::OrthancClient::OrthancConnection& connection, const ::std::string& id) { isReference_ = false; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void**, void*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(19); char* error = function(&pimpl_, connection.pimpl_, id.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Destructs the object. * * Destructs the object. * **/ inline Series::~Series() { if (isReference_) return; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(20); char* error = function(pimpl_); error = error; // Remove warning about unused variable } /** * @brief Reload the instances of this series. * * This method will reload the list of the instances of this series. Pay attention to the fact that the instances that have been previously returned by GetInstance() will be invalidated. * **/ inline void Series::Reload() { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(21); char* error = function(pimpl_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Return the number of instances for this series. * * Return the number of instances for this series. * * @return The number of instances. **/ inline LAAW_UINT32 Series::GetInstanceCount() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(22); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get some instance of this series. * * This method will return an object that contains information about some instance. The instances are indexed by a number between 0 (inclusive) and the result of GetInstanceCount() (exclusive). * * @param index The index of the instance of interest. * @return The instance. **/ inline ::OrthancClient::Instance Series::GetInstance(LAAW_UINT32 index) { void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, void**, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(23); char* error = function(pimpl_, &result_, index); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return ::OrthancClient::Instance(result_); } /** * @brief Get the %Orthanc identifier of this series. * * Get the %Orthanc identifier of this series. * * @return The identifier. **/ inline ::std::string Series::GetId() const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(24); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Returns the URL to this series. * * Returns the URL to this series. * * @return The URL. **/ inline ::std::string Series::GetUrl() const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(25); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Get the value of one of the main DICOM tags for this series. * * Get the value of one of the main DICOM tags for this series. * * @param tag The name of the tag of interest ("Modality", "Manufacturer", "SeriesDate", "SeriesDescription", "SeriesInstanceUID"...). * @param defaultValue The default value to be returned if this tag does not exist. * @return The value of the tag. **/ inline ::std::string Series::GetMainDicomTag(const ::std::string& tag, const ::std::string& defaultValue) const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**, const char*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(26); char* error = function(pimpl_, &result_, tag.c_str(), defaultValue.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Test whether this series encodes a 3D image that can be downloaded from %Orthanc. * * Test whether this series encodes a 3D image that can be downloaded from %Orthanc. * * @return "true" if and only if this is a 3D image. **/ inline bool Series::Is3DImage() { LAAW_INT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_INT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(27); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_ != 0; } /** * @brief Get the width of the 3D image. * * Get the width of the 3D image (i.e. along the X-axis). This call is only valid if this series corresponds to a 3D image. * * @return The width. **/ inline LAAW_UINT32 Series::GetWidth() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(28); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the height of the 3D image. * * Get the height of the 3D image (i.e. along the Y-axis). This call is only valid if this series corresponds to a 3D image. * * @return The height. **/ inline LAAW_UINT32 Series::GetHeight() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(29); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the physical size of a voxel along the X-axis. * * Get the physical size of a voxel along the X-axis. This call is only valid if this series corresponds to a 3D image. * * @return The voxel size. **/ inline float Series::GetVoxelSizeX() { float result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, float*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(30); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the physical size of a voxel along the Y-axis. * * Get the physical size of a voxel along the Y-axis. This call is only valid if this series corresponds to a 3D image. * * @return The voxel size. **/ inline float Series::GetVoxelSizeY() { float result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, float*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(31); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the physical size of a voxel along the Z-axis. * * Get the physical size of a voxel along the Z-axis. This call is only valid if this series corresponds to a 3D image. * * @return The voxel size. **/ inline float Series::GetVoxelSizeZ() { float result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, float*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(32); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Load the 3D image into a memory buffer. * * Load the 3D image into a memory buffer. This call is only valid if this series corresponds to a 3D image. The "target" buffer must be wide enough to store all the voxels of the image. * * @param target The target memory buffer. * @param format The memory layout of the voxels. * @param lineStride The number of bytes between two lines in the target memory buffer. * @param stackStride The number of bytes between two 2D slices in the target memory buffer. **/ inline void Series::Load3DImage(void* target, ::Orthanc::PixelFormat format, LAAW_INT64 lineStride, LAAW_INT64 stackStride) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, void*, LAAW_INT32, LAAW_INT64, LAAW_INT64); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(33); char* error = function(pimpl_, target, format, lineStride, stackStride); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Load the 3D image into a memory buffer. * * Load the 3D image into a memory buffer. This call is only valid if this series corresponds to a 3D image. The "target" buffer must be wide enough to store all the voxels of the image. This method will also update a progress indicator to monitor the loading of the image. * * @param target The target memory buffer. * @param format The memory layout of the voxels. * @param lineStride The number of bytes between two lines in the target memory buffer. * @param stackStride The number of bytes between two 2D slices in the target memory buffer. * @param progress A pointer to a floating-point number that is continuously updated by the download threads to reflect the percentage of completion (between 0 and 1). This value can be read from a separate thread. **/ inline void Series::Load3DImage(void* target, ::Orthanc::PixelFormat format, LAAW_INT64 lineStride, LAAW_INT64 stackStride, float progress[]) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, void*, LAAW_INT32, LAAW_INT64, LAAW_INT64, float*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(34); char* error = function(pimpl_, target, format, lineStride, stackStride, progress); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } } namespace OrthancClient { /** * @brief Create a connection to some study. * * Create a connection to some study. * * @param connection The remote instance of %Orthanc. * @param id The %Orthanc identifier of the study. **/ inline Study::Study(::OrthancClient::OrthancConnection& connection, const ::std::string& id) { isReference_ = false; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void**, void*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(35); char* error = function(&pimpl_, connection.pimpl_, id.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Destructs the object. * * Destructs the object. * **/ inline Study::~Study() { if (isReference_) return; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(36); char* error = function(pimpl_); error = error; // Remove warning about unused variable } /** * @brief Reload the series of this study. * * This method will reload the list of the series of this study. Pay attention to the fact that the series that have been previously returned by GetSeries() will be invalidated. * **/ inline void Study::Reload() { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(37); char* error = function(pimpl_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Return the number of series for this study. * * Return the number of series for this study. * * @return The number of series. **/ inline LAAW_UINT32 Study::GetSeriesCount() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(38); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get some series of this study. * * This method will return an object that contains information about some series. The series are indexed by a number between 0 (inclusive) and the result of GetSeriesCount() (exclusive). * * @param index The index of the series of interest. * @return The series. **/ inline ::OrthancClient::Series Study::GetSeries(LAAW_UINT32 index) { void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, void**, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(39); char* error = function(pimpl_, &result_, index); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return ::OrthancClient::Series(result_); } /** * @brief Get the %Orthanc identifier of this study. * * Get the %Orthanc identifier of this study. * * @return The identifier. **/ inline ::std::string Study::GetId() const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(40); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Get the value of one of the main DICOM tags for this study. * * Get the value of one of the main DICOM tags for this study. * * @param tag The name of the tag of interest ("StudyDate", "StudyDescription", "StudyInstanceUID" or "StudyTime"). * @param defaultValue The default value to be returned if this tag does not exist. * @return The value of the tag. **/ inline ::std::string Study::GetMainDicomTag(const ::std::string& tag, const ::std::string& defaultValue) const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**, const char*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(41); char* error = function(pimpl_, &result_, tag.c_str(), defaultValue.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } } namespace OrthancClient { /** * @brief Create a connection to some image instance. * * Create a connection to some image instance. * * @param connection The remote instance of %Orthanc. * @param id The %Orthanc identifier of the image instance. **/ inline Instance::Instance(::OrthancClient::OrthancConnection& connection, const ::std::string& id) { isReference_ = false; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void**, void*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(42); char* error = function(&pimpl_, connection.pimpl_, id.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Destructs the object. * * Destructs the object. * **/ inline Instance::~Instance() { if (isReference_) return; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(43); char* error = function(pimpl_); error = error; // Remove warning about unused variable } /** * @brief Get the %Orthanc identifier of this identifier. * * Get the %Orthanc identifier of this identifier. * * @return The identifier. **/ inline ::std::string Instance::GetId() const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(44); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Set the extraction mode for the 2D image corresponding to this instance. * * Set the extraction mode for the 2D image corresponding to this instance. * * @param mode The extraction mode. **/ inline void Instance::SetImageExtractionMode(::Orthanc::ImageExtractionMode mode) { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_INT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(45); char* error = function(pimpl_, mode); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Get the extraction mode for the 2D image corresponding to this instance. * * Get the extraction mode for the 2D image corresponding to this instance. * * @return The extraction mode. **/ inline ::Orthanc::ImageExtractionMode Instance::GetImageExtractionMode() const { LAAW_INT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, LAAW_INT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(46); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return static_cast< ::Orthanc::ImageExtractionMode >(result_); } /** * @brief Get the string value of some DICOM tag of this instance. * * Get the string value of some DICOM tag of this instance. * * @param tag The name of the tag of interest. * @return The value of the tag. **/ inline ::std::string Instance::GetTagAsString(const ::std::string& tag) const { const char* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, const char**, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(47); char* error = function(pimpl_, &result_, tag.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return std::string(result_); } /** * @brief Get the floating point value that is stored in some DICOM tag of this instance. * * Get the floating point value that is stored in some DICOM tag of this instance. * * @param tag The name of the tag of interest. * @return The value of the tag. **/ inline float Instance::GetTagAsFloat(const ::std::string& tag) const { float result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, float*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(48); char* error = function(pimpl_, &result_, tag.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the integer value that is stored in some DICOM tag of this instance. * * Get the integer value that is stored in some DICOM tag of this instance. * * @param tag The name of the tag of interest. * @return The value of the tag. **/ inline LAAW_INT32 Instance::GetTagAsInt(const ::std::string& tag) const { LAAW_INT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (const void*, LAAW_INT32*, const char*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(49); char* error = function(pimpl_, &result_, tag.c_str()); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the width of the 2D image. * * Get the width of the 2D image that is encoded by this DICOM instance. * * @return The width. **/ inline LAAW_UINT32 Instance::GetWidth() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(50); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the height of the 2D image. * * Get the height of the 2D image that is encoded by this DICOM instance. * * @return The height. **/ inline LAAW_UINT32 Instance::GetHeight() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(51); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the number of bytes between two lines of the image (pitch). * * Get the number of bytes between two lines of the image in the memory buffer returned by GetBuffer(). This value depends on the extraction mode for the image. * * @return The pitch. **/ inline LAAW_UINT32 Instance::GetPitch() { LAAW_UINT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(52); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get the format of the pixels of the 2D image. * * Return the memory layout that is used for the 2D image that is encoded by this DICOM instance. This value depends on the extraction mode for the image. * * @return The pixel format. **/ inline ::Orthanc::PixelFormat Instance::GetPixelFormat() { LAAW_INT32 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_INT32*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(53); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return static_cast< ::Orthanc::PixelFormat >(result_); } /** * @brief Access the memory buffer in which the raw pixels of the 2D image are stored. * * Access the memory buffer in which the raw pixels of the 2D image are stored. * * @return A pointer to the memory buffer. **/ inline const void* Instance::GetBuffer() { const void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, const void**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(54); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return reinterpret_cast< const void* >(result_); } /** * @brief Access the memory buffer in which the raw pixels of some line of the 2D image are stored. * * Access the memory buffer in which the raw pixels of some line of the 2D image are stored. * * @param y The line of interest. * @return A pointer to the memory buffer. **/ inline const void* Instance::GetBuffer(LAAW_UINT32 y) { const void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, const void**, LAAW_UINT32); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(55); char* error = function(pimpl_, &result_, y); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return reinterpret_cast< const void* >(result_); } /** * @brief Get the size of the DICOM file corresponding to this instance. * * Get the size of the DICOM file corresponding to this instance. * * @return The file size. **/ inline LAAW_UINT64 Instance::GetDicomSize() { LAAW_UINT64 result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, LAAW_UINT64*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(56); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return result_; } /** * @brief Get a pointer to the content of the DICOM file corresponding to this instance. * * Get a pointer to the content of the DICOM file corresponding to this instance. * * @return The DICOM file. **/ inline const void* Instance::GetDicom() { const void* result_; typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*, const void**); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(57); char* error = function(pimpl_, &result_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); return reinterpret_cast< const void* >(result_); } /** * @brief Discard the downloaded 2D image, so as to make room in memory. * * Discard the downloaded 2D image, so as to make room in memory. * **/ inline void Instance::DiscardImage() { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(58); char* error = function(pimpl_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } /** * @brief Discard the downloaded DICOM file, so as to make room in memory. * * Discard the downloaded DICOM file, so as to make room in memory. * **/ inline void Instance::DiscardDicom() { typedef char* (LAAW_ORTHANC_CLIENT_CALL_CONV* Function) (void*); Function function = (Function) ::OrthancClient::Internals::Library::GetInstance().GetFunction(59); char* error = function(pimpl_); ::OrthancClient::Internals::Library::GetInstance().ThrowExceptionIfNeeded(error); } } Orthanc-0.7.2/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows32.def0000644000000000000000000001471712237177136023470 0ustar 00000000000000LIBRARY some.dll EXPORTS _LAAW_EXTERNC_557aee7b61817292a0f31269d3c35db7@8 = LAAW_EXTERNC_557aee7b61817292a0f31269d3c35db7@8 _LAAW_EXTERNC_0b8dff0ce67f10954a49b059e348837e@8 = LAAW_EXTERNC_0b8dff0ce67f10954a49b059e348837e@8 _LAAW_EXTERNC_e05097c153f676e5a5ee54dcfc78256f@4 = LAAW_EXTERNC_e05097c153f676e5a5ee54dcfc78256f@4 _LAAW_EXTERNC_e840242bf58d17d3c1d722da09ce88e0@8 = LAAW_EXTERNC_e840242bf58d17d3c1d722da09ce88e0@8 _LAAW_EXTERNC_c9af31433001b5dfc012a552dc6d0050@8 = LAAW_EXTERNC_c9af31433001b5dfc012a552dc6d0050@8 _LAAW_EXTERNC_3fba4d6b818180a44cd1cae6046334dc@12 = LAAW_EXTERNC_3fba4d6b818180a44cd1cae6046334dc@12 _LAAW_EXTERNC_aeb20dc75b9246188db857317e5e0ce7@8 = LAAW_EXTERNC_aeb20dc75b9246188db857317e5e0ce7@8 _LAAW_EXTERNC_62689803d9871e4d9c51a648640b320b@8 = LAAW_EXTERNC_62689803d9871e4d9c51a648640b320b@8 _LAAW_EXTERNC_2fb64c9e5a67eccd413b0e913469a421@16 = LAAW_EXTERNC_2fb64c9e5a67eccd413b0e913469a421@16 _LAAW_EXTERNC_1f1acb322ea4d0aad65172824607673c@8 = LAAW_EXTERNC_1f1acb322ea4d0aad65172824607673c@8 _LAAW_EXTERNC_f3fd272e4636f6a531aabb72ee01cd5b@16 = LAAW_EXTERNC_f3fd272e4636f6a531aabb72ee01cd5b@16 _LAAW_EXTERNC_12d3de0a96e9efb11136a9811bb9ed38@4 = LAAW_EXTERNC_12d3de0a96e9efb11136a9811bb9ed38@4 _LAAW_EXTERNC_f756172daf04516eec3a566adabb4335@4 = LAAW_EXTERNC_f756172daf04516eec3a566adabb4335@4 _LAAW_EXTERNC_ddb68763ec902a97d579666a73a20118@8 = LAAW_EXTERNC_ddb68763ec902a97d579666a73a20118@8 _LAAW_EXTERNC_fba3c68b4be7558dbc65f7ce1ab57d63@12 = LAAW_EXTERNC_fba3c68b4be7558dbc65f7ce1ab57d63@12 _LAAW_EXTERNC_b4ca99d958f843493e58d1ef967340e1@8 = LAAW_EXTERNC_b4ca99d958f843493e58d1ef967340e1@8 _LAAW_EXTERNC_78d5cc76d282437b6f93ec3b82c35701@16 = LAAW_EXTERNC_78d5cc76d282437b6f93ec3b82c35701@16 _LAAW_EXTERNC_6cf0d7268667f9b0aa4511bacf184919@12 = LAAW_EXTERNC_6cf0d7268667f9b0aa4511bacf184919@12 _LAAW_EXTERNC_7d81cd502ee27e859735d0ea7112b5a1@4 = LAAW_EXTERNC_7d81cd502ee27e859735d0ea7112b5a1@4 _LAAW_EXTERNC_48a2a1a9d68c047e22bfba23014643d2@4 = LAAW_EXTERNC_48a2a1a9d68c047e22bfba23014643d2@4 _LAAW_EXTERNC_852bf8296ca21c5fde5ec565cc10721d@8 = LAAW_EXTERNC_852bf8296ca21c5fde5ec565cc10721d@8 _LAAW_EXTERNC_efd04574e0779faa83df1f2d8f9888db@12 = LAAW_EXTERNC_efd04574e0779faa83df1f2d8f9888db@12 _LAAW_EXTERNC_736247ff5e8036dac38163da6f666ed5@8 = LAAW_EXTERNC_736247ff5e8036dac38163da6f666ed5@8 _LAAW_EXTERNC_d82d2598a7a73f4b6fcc0c09c25b08ca@8 = LAAW_EXTERNC_d82d2598a7a73f4b6fcc0c09c25b08ca@8 _LAAW_EXTERNC_88134b978f9acb2aecdadf54aeab3c64@16 = LAAW_EXTERNC_88134b978f9acb2aecdadf54aeab3c64@16 _LAAW_EXTERNC_152cb1b704c053d24b0dab7461ba6ea3@8 = LAAW_EXTERNC_152cb1b704c053d24b0dab7461ba6ea3@8 _LAAW_EXTERNC_eee03f337ec81d9f1783cd41e5238757@8 = LAAW_EXTERNC_eee03f337ec81d9f1783cd41e5238757@8 _LAAW_EXTERNC_006f08237bd7611636fc721baebfb4c5@8 = LAAW_EXTERNC_006f08237bd7611636fc721baebfb4c5@8 _LAAW_EXTERNC_b794f5cd3dad7d7b575dd1fd902afdd0@8 = LAAW_EXTERNC_b794f5cd3dad7d7b575dd1fd902afdd0@8 _LAAW_EXTERNC_8ee2e50dd9df8f66a3c1766090dd03ab@8 = LAAW_EXTERNC_8ee2e50dd9df8f66a3c1766090dd03ab@8 _LAAW_EXTERNC_046aed35bbe4751691f4c34cc249a61d@8 = LAAW_EXTERNC_046aed35bbe4751691f4c34cc249a61d@8 _LAAW_EXTERNC_4dcc7a0fd025efba251ac6e9b701c2c5@28 = LAAW_EXTERNC_4dcc7a0fd025efba251ac6e9b701c2c5@28 _LAAW_EXTERNC_b2601a161c24ad0a1d3586246f87452c@32 = LAAW_EXTERNC_b2601a161c24ad0a1d3586246f87452c@32 _LAAW_EXTERNC_193599b9e345384fcdfcd47c29c55342@12 = LAAW_EXTERNC_193599b9e345384fcdfcd47c29c55342@12 _LAAW_EXTERNC_7c97f17063a357d38c5fab1136ad12a0@4 = LAAW_EXTERNC_7c97f17063a357d38c5fab1136ad12a0@4 _LAAW_EXTERNC_e65b20b7e0170b67544cd6664a4639b7@4 = LAAW_EXTERNC_e65b20b7e0170b67544cd6664a4639b7@4 _LAAW_EXTERNC_470e981b0e41f17231ba0ae6f3033321@8 = LAAW_EXTERNC_470e981b0e41f17231ba0ae6f3033321@8 _LAAW_EXTERNC_04cefd138b6ea15ad909858f2a0a8f05@12 = LAAW_EXTERNC_04cefd138b6ea15ad909858f2a0a8f05@12 _LAAW_EXTERNC_aee5b1f6f0c082f2c3b0986f9f6a18c7@8 = LAAW_EXTERNC_aee5b1f6f0c082f2c3b0986f9f6a18c7@8 _LAAW_EXTERNC_93965682bace75491413e1f0b8d5a654@16 = LAAW_EXTERNC_93965682bace75491413e1f0b8d5a654@16 _LAAW_EXTERNC_b01c6003238eb46c8db5dc823d7ca678@12 = LAAW_EXTERNC_b01c6003238eb46c8db5dc823d7ca678@12 _LAAW_EXTERNC_0147007fb99bad8cd95a139ec8795376@4 = LAAW_EXTERNC_0147007fb99bad8cd95a139ec8795376@4 _LAAW_EXTERNC_236ee8b403bc99535a8a4695c0cd45cb@8 = LAAW_EXTERNC_236ee8b403bc99535a8a4695c0cd45cb@8 _LAAW_EXTERNC_2a437b7aba6bb01e81113835be8f0146@8 = LAAW_EXTERNC_2a437b7aba6bb01e81113835be8f0146@8 _LAAW_EXTERNC_2bcbcb850934ae0bb4c6f0cc940e6cda@8 = LAAW_EXTERNC_2bcbcb850934ae0bb4c6f0cc940e6cda@8 _LAAW_EXTERNC_8d415c3a78a48e7e61d9fd24e7c79484@12 = LAAW_EXTERNC_8d415c3a78a48e7e61d9fd24e7c79484@12 _LAAW_EXTERNC_70d2f8398bbc63b5f792b69b4ad5fecb@12 = LAAW_EXTERNC_70d2f8398bbc63b5f792b69b4ad5fecb@12 _LAAW_EXTERNC_1729a067d902771517388eedd7346b23@12 = LAAW_EXTERNC_1729a067d902771517388eedd7346b23@12 _LAAW_EXTERNC_72e2aeee66cd3abd8ab7e987321c3745@8 = LAAW_EXTERNC_72e2aeee66cd3abd8ab7e987321c3745@8 _LAAW_EXTERNC_1ea3df5a1ac1a1a687fe7325adddb6f0@8 = LAAW_EXTERNC_1ea3df5a1ac1a1a687fe7325adddb6f0@8 _LAAW_EXTERNC_99b4f370e4f532d8b763e2cb49db92f8@8 = LAAW_EXTERNC_99b4f370e4f532d8b763e2cb49db92f8@8 _LAAW_EXTERNC_c41c742b68617f1c0590577a0a5ebc0c@8 = LAAW_EXTERNC_c41c742b68617f1c0590577a0a5ebc0c@8 _LAAW_EXTERNC_142dd2feba0fc1d262bbd0baeb441a8b@8 = LAAW_EXTERNC_142dd2feba0fc1d262bbd0baeb441a8b@8 _LAAW_EXTERNC_5f5c9f81a4dff8daa6c359f1d0488fef@12 = LAAW_EXTERNC_5f5c9f81a4dff8daa6c359f1d0488fef@12 _LAAW_EXTERNC_9ca979fffd08fa256306d4e68d8b0e91@8 = LAAW_EXTERNC_9ca979fffd08fa256306d4e68d8b0e91@8 _LAAW_EXTERNC_6f2d77a26edc91c28d89408dbc3c271e@8 = LAAW_EXTERNC_6f2d77a26edc91c28d89408dbc3c271e@8 _LAAW_EXTERNC_c0f494b80d4ff8b232df7a75baa0700a@4 = LAAW_EXTERNC_c0f494b80d4ff8b232df7a75baa0700a@4 _LAAW_EXTERNC_d604f44bd5195e082e745e9cbc164f4c@4 = LAAW_EXTERNC_d604f44bd5195e082e745e9cbc164f4c@4 _LAAW_EXTERNC_6c5ad02f91b583e29cebd0bd319ce21d@12 = LAAW_EXTERNC_6c5ad02f91b583e29cebd0bd319ce21d@12 _LAAW_EXTERNC_4068241c44a9c1367fe0e57be523f207@4 = LAAW_EXTERNC_4068241c44a9c1367fe0e57be523f207@4 _LAAW_EXTERNC_GetDescription@0 = LAAW_EXTERNC_GetDescription@0 _LAAW_EXTERNC_GetCompany@0 = LAAW_EXTERNC_GetCompany@0 _LAAW_EXTERNC_GetProduct@0 = LAAW_EXTERNC_GetProduct@0 _LAAW_EXTERNC_GetCopyright@0 = LAAW_EXTERNC_GetCopyright@0 _LAAW_EXTERNC_GetVersion@0 = LAAW_EXTERNC_GetVersion@0 _LAAW_EXTERNC_GetFileVersion@0 = LAAW_EXTERNC_GetFileVersion@0 _LAAW_EXTERNC_GetFullVersion@0 = LAAW_EXTERNC_GetFullVersion@0 _LAAW_EXTERNC_FreeString@4 = LAAW_EXTERNC_FreeString@4 Orthanc-0.7.2/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows32.rc0000644000000000000000000000174412237177136023332 0ustar 00000000000000#include VS_VERSION_INFO VERSIONINFO FILEVERSION 0,7,0,2 PRODUCTVERSION 0,7,0,0 FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "Comments", "Release 0.7.2" VALUE "CompanyName", "CHU of Liege" VALUE "FileDescription", "Native client to the REST API of Orthanc" VALUE "FileVersion", "0.7.0.2" VALUE "InternalName", "OrthancClient" VALUE "LegalCopyright", "(c) 2012-2013, Sebastien Jodogne, CHU of Liege" VALUE "LegalTrademarks", "Licensing information is available on https://code.google.com/p/orthanc/" VALUE "OriginalFilename", "OrthancClient_Windows32.dll" VALUE "ProductName", "OrthancClient" VALUE "ProductVersion", "0.7" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 // U.S. English END END Orthanc-0.7.2/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows64.def0000644000000000000000000000606712237177136023474 0ustar 00000000000000LIBRARY some.dll EXPORTS LAAW_EXTERNC_557aee7b61817292a0f31269d3c35db7 LAAW_EXTERNC_0b8dff0ce67f10954a49b059e348837e LAAW_EXTERNC_e05097c153f676e5a5ee54dcfc78256f LAAW_EXTERNC_e840242bf58d17d3c1d722da09ce88e0 LAAW_EXTERNC_c9af31433001b5dfc012a552dc6d0050 LAAW_EXTERNC_3fba4d6b818180a44cd1cae6046334dc LAAW_EXTERNC_aeb20dc75b9246188db857317e5e0ce7 LAAW_EXTERNC_62689803d9871e4d9c51a648640b320b LAAW_EXTERNC_2fb64c9e5a67eccd413b0e913469a421 LAAW_EXTERNC_1f1acb322ea4d0aad65172824607673c LAAW_EXTERNC_f3fd272e4636f6a531aabb72ee01cd5b LAAW_EXTERNC_12d3de0a96e9efb11136a9811bb9ed38 LAAW_EXTERNC_f756172daf04516eec3a566adabb4335 LAAW_EXTERNC_ddb68763ec902a97d579666a73a20118 LAAW_EXTERNC_fba3c68b4be7558dbc65f7ce1ab57d63 LAAW_EXTERNC_b4ca99d958f843493e58d1ef967340e1 LAAW_EXTERNC_78d5cc76d282437b6f93ec3b82c35701 LAAW_EXTERNC_6cf0d7268667f9b0aa4511bacf184919 LAAW_EXTERNC_7d81cd502ee27e859735d0ea7112b5a1 LAAW_EXTERNC_48a2a1a9d68c047e22bfba23014643d2 LAAW_EXTERNC_852bf8296ca21c5fde5ec565cc10721d LAAW_EXTERNC_efd04574e0779faa83df1f2d8f9888db LAAW_EXTERNC_736247ff5e8036dac38163da6f666ed5 LAAW_EXTERNC_d82d2598a7a73f4b6fcc0c09c25b08ca LAAW_EXTERNC_88134b978f9acb2aecdadf54aeab3c64 LAAW_EXTERNC_152cb1b704c053d24b0dab7461ba6ea3 LAAW_EXTERNC_eee03f337ec81d9f1783cd41e5238757 LAAW_EXTERNC_006f08237bd7611636fc721baebfb4c5 LAAW_EXTERNC_b794f5cd3dad7d7b575dd1fd902afdd0 LAAW_EXTERNC_8ee2e50dd9df8f66a3c1766090dd03ab LAAW_EXTERNC_046aed35bbe4751691f4c34cc249a61d LAAW_EXTERNC_4dcc7a0fd025efba251ac6e9b701c2c5 LAAW_EXTERNC_b2601a161c24ad0a1d3586246f87452c LAAW_EXTERNC_193599b9e345384fcdfcd47c29c55342 LAAW_EXTERNC_7c97f17063a357d38c5fab1136ad12a0 LAAW_EXTERNC_e65b20b7e0170b67544cd6664a4639b7 LAAW_EXTERNC_470e981b0e41f17231ba0ae6f3033321 LAAW_EXTERNC_04cefd138b6ea15ad909858f2a0a8f05 LAAW_EXTERNC_aee5b1f6f0c082f2c3b0986f9f6a18c7 LAAW_EXTERNC_93965682bace75491413e1f0b8d5a654 LAAW_EXTERNC_b01c6003238eb46c8db5dc823d7ca678 LAAW_EXTERNC_0147007fb99bad8cd95a139ec8795376 LAAW_EXTERNC_236ee8b403bc99535a8a4695c0cd45cb LAAW_EXTERNC_2a437b7aba6bb01e81113835be8f0146 LAAW_EXTERNC_2bcbcb850934ae0bb4c6f0cc940e6cda LAAW_EXTERNC_8d415c3a78a48e7e61d9fd24e7c79484 LAAW_EXTERNC_70d2f8398bbc63b5f792b69b4ad5fecb LAAW_EXTERNC_1729a067d902771517388eedd7346b23 LAAW_EXTERNC_72e2aeee66cd3abd8ab7e987321c3745 LAAW_EXTERNC_1ea3df5a1ac1a1a687fe7325adddb6f0 LAAW_EXTERNC_99b4f370e4f532d8b763e2cb49db92f8 LAAW_EXTERNC_c41c742b68617f1c0590577a0a5ebc0c LAAW_EXTERNC_142dd2feba0fc1d262bbd0baeb441a8b LAAW_EXTERNC_5f5c9f81a4dff8daa6c359f1d0488fef LAAW_EXTERNC_9ca979fffd08fa256306d4e68d8b0e91 LAAW_EXTERNC_6f2d77a26edc91c28d89408dbc3c271e LAAW_EXTERNC_c0f494b80d4ff8b232df7a75baa0700a LAAW_EXTERNC_d604f44bd5195e082e745e9cbc164f4c LAAW_EXTERNC_6c5ad02f91b583e29cebd0bd319ce21d LAAW_EXTERNC_4068241c44a9c1367fe0e57be523f207 LAAW_EXTERNC_GetDescription LAAW_EXTERNC_GetCompany LAAW_EXTERNC_GetProduct LAAW_EXTERNC_GetCopyright LAAW_EXTERNC_GetVersion LAAW_EXTERNC_GetFileVersion LAAW_EXTERNC_GetFullVersion LAAW_EXTERNC_FreeString Orthanc-0.7.2/OrthancCppClient/SharedLibrary/AUTOGENERATED/Windows64.rc0000644000000000000000000000174412237177136023337 0ustar 00000000000000#include VS_VERSION_INFO VERSIONINFO FILEVERSION 0,7,0,2 PRODUCTVERSION 0,7,0,0 FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "Comments", "Release 0.7.2" VALUE "CompanyName", "CHU of Liege" VALUE "FileDescription", "Native client to the REST API of Orthanc" VALUE "FileVersion", "0.7.0.2" VALUE "InternalName", "OrthancClient" VALUE "LegalCopyright", "(c) 2012-2013, Sebastien Jodogne, CHU of Liege" VALUE "LegalTrademarks", "Licensing information is available on https://code.google.com/p/orthanc/" VALUE "OriginalFilename", "OrthancClient_Windows64.dll" VALUE "ProductName", "OrthancClient" VALUE "ProductVersion", "0.7" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 // U.S. English END END Orthanc-0.7.2/OrthancCppClient/SharedLibrary/ConfigurationCpp.json0000644000000000000000000000023412237177136023354 0ustar 00000000000000{ "InternalsNamespace" : [ "OrthancClient", "Internals" ], "PublicNamespace" : [ "OrthancClient" ], "ExceptionClassName" : "OrthancClientException" } Orthanc-0.7.2/OrthancCppClient/SharedLibrary/Generate.sh0000755000000000000000000000231112237177136021276 0ustar 00000000000000#!/bin/bash set -e mkdir -p AUTOGENERATED LAAW_ROOT=~/Subversion/Jomago/Src/Labo/Laaw ${LAAW_ROOT}/Parser/Build/LaawParser.exe AUTOGENERATED/CodeModelRaw.json ../OrthancConnection.h -I`pwd`/../../s/jsoncpp-src-0.6.0-rc2/include -fms-extensions python ${LAAW_ROOT}/Generators/CodeModelPostProcessing.py AUTOGENERATED/CodeModel.json AUTOGENERATED/CodeModelRaw.json Product.json python ${LAAW_ROOT}/Generators/GenerateWrapperCpp.py AUTOGENERATED/OrthancCppClient.h AUTOGENERATED/CodeModel.json Product.json ConfigurationCpp.json python ${LAAW_ROOT}/Generators/GenerateExternC.py AUTOGENERATED/ExternC.cpp AUTOGENERATED/CodeModel.json Product.json python ${LAAW_ROOT}/Generators/GenerateWindows32Def.py AUTOGENERATED/Windows32.def AUTOGENERATED/CodeModel.json python ${LAAW_ROOT}/Generators/GenerateWindows64Def.py AUTOGENERATED/Windows64.def AUTOGENERATED/CodeModel.json python ${LAAW_ROOT}/Generators/ApplyProductSubstitutions.py AUTOGENERATED/Windows32.rc ${LAAW_ROOT}/Resources/DllResources.rc.mustache Product.json PLATFORM_SUFFIX "_Windows32" python ${LAAW_ROOT}/Generators/ApplyProductSubstitutions.py AUTOGENERATED/Windows64.rc ${LAAW_ROOT}/Resources/DllResources.rc.mustache Product.json PLATFORM_SUFFIX "_Windows64" Orthanc-0.7.2/OrthancCppClient/SharedLibrary/Laaw/VersionScript.map0000644000000000000000000000011012237177136023375 0ustar 00000000000000# This is a version-script { global: LAAW_EXTERNC_*; local: *; }; Orthanc-0.7.2/OrthancCppClient/SharedLibrary/Laaw/laaw-exports.h0000644000000000000000000000552712237177136022704 0ustar 00000000000000/** * Laaw - Lightweight, Automated API Wrapper * Copyright (C) 2010-2013 Jomago - Alain Mazy, Benjamin Golinvaux, * Sebastien Jodogne * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 /******************************************************************** ** Windows target ********************************************************************/ #if defined _WIN32 #include #if defined(__GNUC__) // This is Mingw #define LAAW_EXPORT_DLL_API // The exports are handled by the .DEF file #else // This is MSVC #define LAAW_EXPORT_DLL_API __declspec(dllexport) #endif #ifdef _M_X64 // 64 bits target #define LAAW_CALL_CONVENTION #else // 32 bits target #define LAAW_CALL_CONVENTION __stdcall // Use the StdCall in Windows32 (for VB6) #endif /******************************************************************** ** Linux target ********************************************************************/ #elif defined(__linux) // Try the gcc visibility support // http://gcc.gnu.org/wiki/Visibility #if ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) #define LAAW_EXPORT_DLL_API __attribute__ ((visibility("default"))) #define LAAW_CALL_CONVENTION #else #error No support for visibility in your version of GCC #endif /******************************************************************** ** Max OS X target ********************************************************************/ #else #define LAAW_EXPORT_DLL_API __attribute__ ((visibility("default"))) #define LAAW_CALL_CONVENTION #endif Orthanc-0.7.2/OrthancCppClient/SharedLibrary/Laaw/laaw.h0000644000000000000000000000514212237177136021173 0ustar 00000000000000/** * Laaw - Lightweight, Automated API Wrapper * Copyright (C) 2010-2013 Jomago - Alain Mazy, Benjamin Golinvaux, * Sebastien Jodogne * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "laaw-exports.h" #include #include #if (LAAW_PARSING == 1) #define LAAW_API __attribute__((deprecated(""))) #define LAAW_API_INTERNAL __attribute__((deprecated(""))) #define LAAW_API_OVERLOAD(name) __attribute__((deprecated(""))) #define LAAW_API_PROPERTY __attribute__((deprecated(""))) #define LAAW_API_STATIC_CLASS __attribute__((deprecated(""))) #define LAAW_API_CUSTOM(name, value) __attribute__((deprecated(""))) #else #define LAAW_API #define LAAW_API_INTERNAL #define LAAW_API_OVERLOAD(name) #define LAAW_API_PROPERTY #define LAAW_API_STATIC_CLASS #define LAAW_API_CUSTOM(name, value) #endif namespace Laaw { /** * This is the base class from which all the public exceptions in * the SDK should derive. **/ class LaawException { private: std::string what_; public: LaawException() { } LaawException(const std::string& what) : what_(what) { } LaawException(const char* what) : what_(what) { } virtual const char* What() const { return what_.c_str(); } }; } Orthanc-0.7.2/OrthancCppClient/SharedLibrary/Product.json0000644000000000000000000000045712237177136021531 0ustar 00000000000000{ "Product" : "OrthancClient", "Description" : "Native client to the REST API of Orthanc", "Company" : "CHU of Liege", "Copyright" : "(c) 2012-2013, Sebastien Jodogne, CHU of Liege", "Legal" : "Licensing information is available on https://code.google.com/p/orthanc/", "Version" : "0.7.2" } Orthanc-0.7.2/OrthancCppClient/SharedLibrary/SharedLibrary.cpp0000644000000000000000000000356212237177136022455 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "../../Core/HttpClient.h" #include "../OrthancConnection.h" class SharedLibrarySingleton { public: SharedLibrarySingleton() { Orthanc::HttpClient::GlobalInitialize(); } ~SharedLibrarySingleton() { Orthanc::HttpClient::GlobalFinalize(); } }; static SharedLibrarySingleton singleton_; #include "AUTOGENERATED/ExternC.cpp" Orthanc-0.7.2/OrthancCppClient/Study.cpp0000644000000000000000000000516612237177136016301 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Study.h" #include "OrthancConnection.h" namespace OrthancClient { void Study::ReadStudy() { Orthanc::HttpClient client(connection_.GetHttpClient()); client.SetUrl(std::string(connection_.GetOrthancUrl()) + "/studies/" + id_); Json::Value v; if (!client.Apply(study_)) { throw OrthancClientException(Orthanc::ErrorCode_NetworkProtocol); } } Orthanc::IDynamicObject* Study::GetFillerItem(size_t index) { Json::Value::ArrayIndex tmp = static_cast(index); std::string id = study_["Series"][tmp].asString(); return new Series(connection_, id.c_str()); } Study::Study(const OrthancConnection& connection, const char* id) : connection_(connection), id_(id), series_(*this) { series_.SetThreadCount(connection.GetThreadCount()); ReadStudy(); } const char* Study::GetMainDicomTag(const char* tag, const char* defaultValue) const { if (study_["MainDicomTags"].isMember(tag)) { return study_["MainDicomTags"][tag].asCString(); } else { return defaultValue; } } } Orthanc-0.7.2/OrthancCppClient/Study.h0000644000000000000000000001005212237177136015734 0ustar 00000000000000/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, * Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General 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 "Series.h" namespace OrthancClient { /** * {summary}{Connection to a study stored in %Orthanc.} * {description}{This class encapsulates a connection to a study * from a remote instance of %Orthanc.} **/ class LAAW_API Study : public Orthanc::IDynamicObject, private Orthanc::ArrayFilledByThreads::IFiller { private: const OrthancConnection& connection_; std::string id_; Json::Value study_; Orthanc::ArrayFilledByThreads series_; void ReadStudy(); virtual size_t GetFillerSize() { return study_["Series"].size(); } virtual Orthanc::IDynamicObject* GetFillerItem(size_t index); public: /** * {summary}{Create a connection to some study.} * {param}{connection The remote instance of %Orthanc.} * {param}{id The %Orthanc identifier of the study.} **/ Study(const OrthancConnection& connection, const char* id); /** * {summary}{Reload the series of this study.} * {description}{This method will reload the list of the series of this study. Pay attention to the fact that the series that have been previously returned by GetSeries() will be invalidated.} **/ void Reload() { series_.Reload(); } /** * {summary}{Return the number of series for this study.} * {returns}{The number of series.} **/ uint32_t GetSeriesCount() { return series_.GetSize(); } /** * {summary}{Get some series of this study.} * {description}{This method will return an object that contains information about some series. The series are indexed by a number between 0 (inclusive) and the result of GetSeriesCount() (exclusive).} * {param}{index The index of the series of interest.} * {returns}{The series.} **/ Series& GetSeries(uint32_t index) { return dynamic_cast(series_.GetItem(index)); } /** * {summary}{Get the %Orthanc identifier of this study.} * {returns}{The identifier.} **/ const char* GetId() const { return id_.c_str(); } /** * {summary}{Get the value of one of the main DICOM tags for this study.} * {param}{tag The name of the tag of interest ("StudyDate", "StudyDescription", "StudyInstanceUID" or "StudyTime").} * {param}{defaultValue The default value to be returned if this tag does not exist.} * {returns}{The value of the tag.} **/ const char* GetMainDicomTag(const char* tag, const char* defaultValue) const; }; } Orthanc-0.7.2/OrthancExplorer/explorer.css0000644000000000000000000000124012237177136016743 0ustar 00000000000000ul.tree ul { margin-left: 36px; } #progress { position: relative; /*height: 2em; */ width: 100%; background-color: grey; height: 2.5em; } #progress .label { z-index: 10; position: absolute; left:0; top: 0; width: 100%; font-weight: bold; text-align: center; text-shadow: none; padding: .5em; color: white; } #progress .bar { z-index: 0; position: absolute; left:0; top: 0; height: 100%; width: 0%; background-color: green; } .ui-title a { text-decoration: none; color: white !important; } .switch-container .ui-slider-switch { width: 100%; }Orthanc-0.7.2/OrthancExplorer/explorer.html0000644000000000000000000003122612237177136017126 0ustar 00000000000000 Orthanc Explorer

Find a patient

Upload DICOM

Upload DICOM files

Find patient

  • Drag and drop DICOM files here
Orthanc-0.7.2/OrthancExplorer/explorer.js0000644000000000000000000006303712237177136016603 0ustar 00000000000000// http://stackoverflow.com/questions/1663741/is-there-a-good-jquery-drag-and-drop-file-upload-plugin // Forbid the access to IE if ($.browser.msie) { alert("Please use Mozilla Firefox or Google Chrome. Microsoft Internet Explorer is not supported."); } // http://jquerymobile.com/demos/1.1.0/docs/api/globalconfig.html //$.mobile.ajaxEnabled = false; //$.mobile.page.prototype.options.addBackBtn = true; //$.mobile.defaultPageTransition = 'slide'; var currentPage = ''; var currentUuid = ''; // http://stackoverflow.com/a/4673436 String.prototype.format = function() { var args = arguments; return this.replace(/{(\d+)}/g, function(match, number) { /*return typeof args[number] != 'undefined' ? args[number] : match;*/ return args[number]; }); }; $(document).ready(function() { var $tree = $('#dicom-tree'); $tree.tree({ autoEscape: false }); $('#dicom-tree').bind( 'tree.click', function(event) { if (event.node.is_open) $tree.tree('closeNode', event.node, true); else $tree.tree('openNode', event.node, true); } ); }); function SplitLongUid(s) { return '' + s.substr(0, s.length / 2) + ' ' + s.substr(s.length / 2, s.length - s.length / 2) + ''; } function ParseDicomDate(s) { y = parseInt(s.substr(0, 4), 10); m = parseInt(s.substr(4, 2), 10) - 1; d = parseInt(s.substr(6, 2), 10); if (y == null || m == null || d == null || !isFinite(y) || !isFinite(m) || !isFinite(d)) { return null; } if (y < 1900 || y > 2100 || m < 0 || m >= 12 || d <= 0 || d >= 32) { return null; } return new Date(y, m, d); } function FormatDicomDate(s) { if (s == undefined) return "No date"; var d = ParseDicomDate(s); if (d == null) return '?'; else return d.toString('dddd, MMMM d, yyyy'); } function Sort(arr, fieldExtractor, isInteger, reverse) { var defaultValue; if (isInteger) defaultValue = 0; else defaultValue = ''; arr.sort(function(a, b) { var ta = fieldExtractor(a); var tb = fieldExtractor(b); var order; if (ta == undefined) ta = defaultValue; if (tb == undefined) tb = defaultValue; if (isInteger) { ta = parseInt(ta, 10); tb = parseInt(tb, 10); order = ta - tb; } else { if (ta < tb) order = -1; else if (ta > tb) order = 1; else order = 0; } if (reverse) return -order; else return order; }); } function SortOnDicomTag(arr, tag, isInteger, reverse) { return Sort(arr, function(a) { return a.MainDicomTags[tag]; }, isInteger, reverse); } function GetSingleResource(type, uuid, callback) { var resource = null; $.ajax({ url: '../' + type + '/' + uuid, dataType: 'json', async: false, cache: false, success: function(s) { callback(s); } }); } function GetMultipleResources(type, uuids, callback) { if (uuids == null) { $.ajax({ url: '../' + type, dataType: 'json', async: false, cache: false, success: function(s) { uuids = s; } }); } var resources = []; var ajaxRequests = uuids.map(function(uuid) { return $.ajax({ url: '../' + type + '/' + uuid, dataType: 'json', async: true, cache: false, success: function(s) { resources.push(s); } }); }); // Wait for all the AJAX requests to end $.when.apply($, ajaxRequests).then(function() { callback(resources); }); } function CompleteFormatting(s, link, isReverse) { if (link != null) { s = 'href="' + link + '">' + s + ''; if (isReverse) s = 'data-direction="reverse" '+ s; s = '' + s + ''; else return '
  • ' + s + '
  • '; } function FormatMainDicomTags(tags, tagsToIgnore) { var s = ''; for (var i in tags) { if (tagsToIgnore.indexOf(i) == -1) { var v = tags[i]; if (i == "PatientBirthDate" || i == "StudyDate" || i == "SeriesDate") { v = FormatDicomDate(v); } else if (i == "DicomStudyInstanceUID" || i == "DicomSeriesInstanceUID") { v = SplitLongUid(v); } s += ('

    {0}: {1}

    ').format(i, v); } } return s; } function FormatPatient(patient, link, isReverse) { var s = ('

    {0}

    {1}' + '{2}' ).format (patient.MainDicomTags.PatientName, FormatMainDicomTags(patient.MainDicomTags, [ "PatientName", "OtherPatientIDs" ]), patient.Studies.length ); return CompleteFormatting(s, link, isReverse); } function FormatStudy(study, link, isReverse) { var s = ('

    {0}

    {1}' + '{2}' ).format (study.MainDicomTags.StudyDescription, FormatMainDicomTags(study.MainDicomTags, [ "StudyDescription", "StudyTime" ]), study.Series.length ); return CompleteFormatting(s, link, isReverse); } function FormatSeries(series, link, isReverse) { var c; if (series.ExpectedNumberOfInstances == null || series.Instances.length == series.ExpectedNumberOfInstances) { c = series.Instances.length; } else { c = series.Instances.length + '/' + series.ExpectedNumberOfInstances; } var s = ('

    {0}

    ' + '

    Status: {1}

    {2}' + '{3}').format (series.MainDicomTags.SeriesDescription, series.Status, FormatMainDicomTags(series.MainDicomTags, [ "SeriesDescription", "SeriesTime", "Manufacturer", "ImagesInAcquisition", "SeriesDate" ]), c ); return CompleteFormatting(s, link, isReverse); } function FormatInstance(instance, link, isReverse) { var s = ('

    Instance {0}

    {1}').format (instance.IndexInSeries, FormatMainDicomTags(instance.MainDicomTags, [ "AcquisitionNumber", "InstanceNumber", "InstanceCreationDate", "InstanceCreationTime" ]) ); return CompleteFormatting(s, link, isReverse); } $('[data-role="page"]').live('pagebeforeshow', function() { $.ajax({ url: '../system', dataType: 'json', async: false, cache: false, success: function(s) { if (s.Name != "") { $('.orthanc-name').html('
    ' + s.Name + ' » '); } } }); }); $('#find-patients').live('pagebeforeshow', function() { GetMultipleResources('patients', null, function(patients) { var target = $('#all-patients'); $('li', target).remove(); SortOnDicomTag(patients, 'PatientName', false, false); for (var i = 0; i < patients.length; i++) { var p = FormatPatient(patients[i], '#patient?uuid=' + patients[i].ID); target.append(p); } target.listview('refresh'); }); }); function SetupAnonymizedOrModifiedFrom(buttonSelector, resource, resourceType, field) { if (field in resource) { $(buttonSelector).closest('li').show(); $(buttonSelector).click(function(e) { window.location.assign('explorer.html#' + resourceType + '?uuid=' + resource[field]); }); } else { $(buttonSelector).closest('li').hide(); } } function RefreshPatient() { if ($.mobile.pageData) { GetSingleResource('patients', $.mobile.pageData.uuid, function(patient) { GetMultipleResources('studies', patient.Studies, function(studies) { SortOnDicomTag(studies, 'StudyDate', false, true); $('#patient-info li').remove(); $('#patient-info') .append('
  • Patient
  • ') .append(FormatPatient(patient)) .listview('refresh'); var target = $('#list-studies'); $('li', target).remove(); for (var i = 0; i < studies.length; i++) { if (i == 0 || studies[i].MainDicomTags.StudyDate != studies[i - 1].MainDicomTags.StudyDate) { target.append('
  • {0}
  • '.format (FormatDicomDate(studies[i].MainDicomTags.StudyDate))); } target.append(FormatStudy(studies[i], '#study?uuid=' + studies[i].ID)); } SetupAnonymizedOrModifiedFrom('#patient-anonymized-from', patient, 'patient', 'AnonymizedFrom'); SetupAnonymizedOrModifiedFrom('#patient-modified-from', patient, 'patient', 'ModifiedFrom'); target.listview('refresh'); // Check whether this patient is protected $.ajax({ url: '../patients/' + $.mobile.pageData.uuid + '/protected', type: 'GET', dataType: 'text', async: false, cache: false, success: function (s) { var v = (s == '1') ? 'on' : 'off'; $('#protection').val(v).slider('refresh'); } }); currentPage = 'patient'; currentUuid = $.mobile.pageData.uuid; }); }); } } function RefreshStudy() { if ($.mobile.pageData) { GetSingleResource('studies', $.mobile.pageData.uuid, function(study) { GetSingleResource('patients', study.ParentPatient, function(patient) { GetMultipleResources('series', study.Series, function(series) { SortOnDicomTag(series, 'SeriesDate', false, true); $('#study .patient-link').attr('href', '#patient?uuid=' + patient.ID); $('#study-info li').remove(); $('#study-info') .append('
  • Patient
  • ') .append(FormatPatient(patient, '#patient?uuid=' + patient.ID, true)) .append('
  • Study
  • ') .append(FormatStudy(study)) .listview('refresh'); SetupAnonymizedOrModifiedFrom('#study-anonymized-from', study, 'study', 'AnonymizedFrom'); SetupAnonymizedOrModifiedFrom('#study-modified-from', study, 'study', 'ModifiedFrom'); var target = $('#list-series'); $('li', target).remove(); for (var i = 0; i < series.length; i++) { if (i == 0 || series[i].MainDicomTags.SeriesDate != series[i - 1].MainDicomTags.SeriesDate) { target.append('
  • {0}
  • '.format (FormatDicomDate(series[i].MainDicomTags.SeriesDate))); } target.append(FormatSeries(series[i], '#series?uuid=' + series[i].ID)); } target.listview('refresh'); currentPage = 'study'; currentUuid = $.mobile.pageData.uuid; }); }); }); } } function RefreshSeries() { if ($.mobile.pageData) { GetSingleResource('series', $.mobile.pageData.uuid, function(series) { GetSingleResource('studies', series.ParentStudy, function(study) { GetSingleResource('patients', study.ParentPatient, function(patient) { GetMultipleResources('instances', series.Instances, function(instances) { Sort(instances, function(x) { return x.IndexInSeries; }, true, false); $('#series .patient-link').attr('href', '#patient?uuid=' + patient.ID); $('#series .study-link').attr('href', '#study?uuid=' + study.ID); $('#series-info li').remove(); $('#series-info') .append('
  • Patient
  • ') .append(FormatPatient(patient, '#patient?uuid=' + patient.ID, true)) .append('
  • Study
  • ') .append(FormatStudy(study, '#study?uuid=' + study.ID, true)) .append('
  • Series
  • ') .append(FormatSeries(series)) .listview('refresh'); SetupAnonymizedOrModifiedFrom('#series-anonymized-from', series, 'series', 'AnonymizedFrom'); SetupAnonymizedOrModifiedFrom('#series-modified-from', series, 'series', 'ModifiedFrom'); var target = $('#list-instances'); $('li', target).remove(); for (var i = 0; i < instances.length; i++) { target.append(FormatInstance(instances[i], '#instance?uuid=' + instances[i].ID)); } target.listview('refresh'); currentPage = 'series'; currentUuid = $.mobile.pageData.uuid; }); }); }); }); } } function ConvertForTree(dicom) { var result = []; for (var i in dicom) { if (dicom[i] != null) { var label = i + ' (' + dicom[i]["Name"] + '): '; if (dicom[i]["Type"] == 'String') { result.push({ label: label + '' + dicom[i]["Value"] + '', children: [] }); } else if (dicom[i]["Type"] == 'TooLong') { result.push({ label: label + 'Too long', children: [] }); } else if (dicom[i]["Type"] == 'Null') { result.push({ label: label + 'Null', children: [] }); } else if (dicom[i]["Type"] == 'Sequence') { var c = []; for (var j = 0; j < dicom[i]["Value"].length; j++) { c.push({ label: 'Item ' + j, children: ConvertForTree(dicom[i]["Value"][j]) }); } result.push({ label: label + '[]', children: c }); } } } return result; } function RefreshInstance() { if ($.mobile.pageData) { GetSingleResource('instances', $.mobile.pageData.uuid, function(instance) { GetSingleResource('series', instance.ParentSeries, function(series) { GetSingleResource('studies', series.ParentStudy, function(study) { GetSingleResource('patients', study.ParentPatient, function(patient) { $('#instance .patient-link').attr('href', '#patient?uuid=' + patient.ID); $('#instance .study-link').attr('href', '#study?uuid=' + study.ID); $('#instance .series-link').attr('href', '#series?uuid=' + series.ID); $('#instance-info li').remove(); $('#instance-info') .append('
  • Patient
  • ') .append(FormatPatient(patient, '#patient?uuid=' + patient.ID, true)) .append('
  • Study
  • ') .append(FormatStudy(study, '#study?uuid=' + study.ID, true)) .append('
  • Series
  • ') .append(FormatSeries(series, '#series?uuid=' + series.ID, true)) .append('
  • Instance
  • ') .append(FormatInstance(instance)) .listview('refresh'); $.ajax({ url: '../instances/' + instance.ID + '/tags', cache: false, dataType: 'json', success: function(s) { $('#dicom-tree').tree('loadData', ConvertForTree(s)); } }); SetupAnonymizedOrModifiedFrom('#instance-anonymized-from', instance, 'instance', 'AnonymizedFrom'); SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', 'ModifiedFrom'); currentPage = 'instance'; currentUuid = $.mobile.pageData.uuid; }); }); }); }); } } $(document).live('pagebeforehide', function() { currentPage = ''; currentUuid = ''; }); $('#patient').live('pagebeforeshow', RefreshPatient); $('#study').live('pagebeforeshow', RefreshStudy); $('#series').live('pagebeforeshow', RefreshSeries); $('#instance').live('pagebeforeshow', RefreshInstance); $(function() { $(window).hashchange(function(e, data) { // This fixes the navigation with the back button and with the anonymization if ('uuid' in $.mobile.pageData && currentPage == $.mobile.pageData.active && currentUuid != $.mobile.pageData.uuid) { if (currentPage == 'patient') RefreshPatient(); else if (currentPage == 'study') RefreshStudy(); else if (currentPage == 'series') RefreshSeries(); else if (currentPage == 'instance') RefreshInstance(); } }); }); function DeleteResource(path) { $.ajax({ url: path, type: 'DELETE', dataType: 'json', async: false, success: function(s) { var ancestor = s.RemainingAncestor; if (ancestor == null) $.mobile.changePage('#find-patients'); else $.mobile.changePage('#' + ancestor.Type.toLowerCase() + '?uuid=' + ancestor.ID); } }); } function OpenDeleteResourceDialog(path, title) { $(document).simpledialog2({ // http://dev.jtsage.com/jQM-SimpleDialog/demos2/ // http://dev.jtsage.com/jQM-SimpleDialog/demos2/options.html mode: 'button', animate: false, headerText: title, headerClose: true, width: '500px', buttons : { 'OK': { click: function () { DeleteResource(path); }, icon: "delete", theme: "c" }, 'Cancel': { click: function () { } } } }); } $('#instance-delete').live('click', function() { OpenDeleteResourceDialog('../instances/' + $.mobile.pageData.uuid, 'Delete this instance?'); }); $('#study-delete').live('click', function() { OpenDeleteResourceDialog('../studies/' + $.mobile.pageData.uuid, 'Delete this study?'); }); $('#series-delete').live('click', function() { OpenDeleteResourceDialog('../series/' + $.mobile.pageData.uuid, 'Delete this series?'); }); $('#patient-delete').live('click', function() { OpenDeleteResourceDialog('../patients/' + $.mobile.pageData.uuid, 'Delete this patient?'); }); $('#instance-download-dicom').live('click', function(e) { // http://stackoverflow.com/a/1296101 e.preventDefault(); //stop the browser from following window.location.href = '../instances/' + $.mobile.pageData.uuid + '/file'; }); $('#instance-download-json').live('click', function(e) { // http://stackoverflow.com/a/1296101 e.preventDefault(); //stop the browser from following window.location.href = '../instances/' + $.mobile.pageData.uuid + '/tags'; }); $('#instance-preview').live('click', function(e) { if ($.mobile.pageData) { GetSingleResource('instances', $.mobile.pageData.uuid + '/frames', function(frames) { if (frames.length == 1) { // Viewing a single-frame image jQuery.slimbox('../instances/' + $.mobile.pageData.uuid + '/preview', '', { overlayFadeDuration : 1, resizeDuration : 1, imageFadeDuration : 1 }); } else { // Viewing a multi-frame image var images = []; for (var i = 0; i < frames.length; i++) { images.push([ '../instances/' + $.mobile.pageData.uuid + '/frames/' + i + '/preview' ]); } jQuery.slimbox(images, 0, { overlayFadeDuration : 1, resizeDuration : 1, imageFadeDuration : 1, loop : true }); } }); } }); $('#series-preview').live('click', function(e) { if ($.mobile.pageData) { GetSingleResource('series', $.mobile.pageData.uuid, function(series) { GetMultipleResources('instances', series.Instances, function(instances) { Sort(instances, function(x) { return x.IndexInSeries; }, true, false); var images = []; for (var i = 0; i < instances.length; i++) { images.push([ '../instances/' + instances[i].ID + '/preview', '{0}/{1}'.format(i + 1, instances.length) ]) } jQuery.slimbox(images, 0, { overlayFadeDuration : 1, resizeDuration : 1, imageFadeDuration : 1, loop : true }); }) }); } }); function ChooseDicomModality(callback) { var clickedModality = ''; var clickedPeer = ''; var items = $('
      ') .attr('data-divider-theme', 'd') .attr('data-role', 'listview'); // Retrieve the list of the known DICOM modalities $.ajax({ url: '../modalities', type: 'GET', dataType: 'json', async: false, cache: false, success: function(modalities) { if (modalities.length > 0) { items.append('
    • DICOM modalities
    • '); for (var i = 0; i < modalities.length; i++) { var name = modalities[i]; var item = $('
    • ') .html('' + name + '') .attr('name', name) .click(function() { clickedModality = $(this).attr('name'); }); items.append(item); } } // Retrieve the list of the known Orthanc peers $.ajax({ url: '../peers', type: 'GET', dataType: 'json', async: false, cache: false, success: function(peers) { if (peers.length > 0) { items.append('
    • Orthanc peers
    • '); for (var i = 0; i < peers.length; i++) { var name = peers[i]; var item = $('
    • ') .html('' + name + '') .attr('name', name) .click(function() { clickedPeer = $(this).attr('name'); }); items.append(item); } } // Launch the dialog $('#dialog').simpledialog2({ mode: 'blank', animate: false, headerText: 'Choose target', headerClose: true, forceInput: false, width: '100%', blankContent: items, callbackClose: function() { var timer; function WaitForDialogToClose() { if (!$('#dialog').is(':visible')) { clearInterval(timer); callback(clickedModality, clickedPeer); } } timer = setInterval(WaitForDialogToClose, 100); } }); } }); } }); } $('#instance-store,#series-store,#study-store,#patient-store').live('click', function(e) { ChooseDicomModality(function(modality, peer) { var url; var loading; if (modality != '') { url = '../modalities/' + modality + '/store'; loading = '#dicom-store'; } if (peer != '') { url = '../peers/' + peer + '/store'; loading = '#peer-store'; } if (url != '') { $.ajax({ url: url, type: 'POST', dataType: 'text', data: $.mobile.pageData.uuid, async: true, // Necessary to block UI beforeSend: function() { $.blockUI({ message: $(loading) }); }, complete: function(s) { $.unblockUI(); }, success: function(s) { }, error: function() { alert('Error during store'); } }); } }); }); $('#show-tag-name').live('change', function(e) { var checked = e.currentTarget.checked; if (checked) $('.tag-name').show(); else $('.tag-name').hide(); }); $('#patient-archive').live('click', function(e) { e.preventDefault(); //stop the browser from following window.location.href = '../patients/' + $.mobile.pageData.uuid + '/archive'; }); $('#study-archive').live('click', function(e) { e.preventDefault(); //stop the browser from following window.location.href = '../studies/' + $.mobile.pageData.uuid + '/archive'; }); $('#series-archive').live('click', function(e) { e.preventDefault(); //stop the browser from following window.location.href = '../series/' + $.mobile.pageData.uuid + '/archive'; }); $('#protection').live('change', function(e) { var isProtected = e.target.value == "on"; $.ajax({ url: '../patients/' + $.mobile.pageData.uuid + '/protected', type: 'PUT', dataType: 'text', data: isProtected ? '1' : '0', async: false }); }); function OpenAnonymizeResourceDialog(path, title) { $(document).simpledialog2({ mode: 'button', animate: false, headerText: title, headerClose: true, width: '500px', buttons : { 'OK': { click: function () { $.ajax({ url: path + '/anonymize', type: 'POST', data: '{ "Keep" : [ "SeriesDescription", "StudyDescription" ] }', dataType: 'json', async: false, cache: false, success: function(s) { // The following line does not work... //$.mobile.changePage('explorer.html#patient?uuid=' + s.PatientID); window.location.assign('explorer.html#patient?uuid=' + s.PatientID); //window.location.reload(); } }); }, icon: "delete", theme: "c" }, 'Cancel': { click: function () { } } } }); } $('#instance-anonymize').live('click', function() { OpenAnonymizeResourceDialog('../instances/' + $.mobile.pageData.uuid, 'Anonymize this instance?'); }); $('#study-anonymize').live('click', function() { OpenAnonymizeResourceDialog('../studies/' + $.mobile.pageData.uuid, 'Anonymize this study?'); }); $('#series-anonymize').live('click', function() { OpenAnonymizeResourceDialog('../series/' + $.mobile.pageData.uuid, 'Anonymize this series?'); }); $('#patient-anonymize').live('click', function() { OpenAnonymizeResourceDialog('../patients/' + $.mobile.pageData.uuid, 'Anonymize this patient?'); }); Orthanc-0.7.2/OrthancExplorer/file-upload.js0000644000000000000000000000472312237177136017141 0ustar 00000000000000var pendingUploads = []; var currentUpload = 0; var totalUpload = 0; $(document).ready(function() { // Initialize the jQuery File Upload widget: $('#fileupload').fileupload({ //dataType: 'json', //maxChunkSize: 500, //sequentialUploads: true, limitConcurrentUploads: 3, add: function (e, data) { pendingUploads.push(data); } }) .bind('fileuploadstop', function(e, data) { $('#upload-button').removeClass('ui-disabled'); //$('#upload-abort').addClass('ui-disabled'); $('#progress .bar').css('width', '100%'); if ($('#progress .label').text() != 'Failure') $('#progress .label').text('Done'); }) .bind('fileuploadfail', function(e, data) { $('#progress .bar') .css('width', '100%') .css('background-color', 'red'); $('#progress .label').text('Failure'); }) .bind('fileuploaddrop', function (e, data) { var target = $('#upload-list'); $.each(data.files, function (index, file) { target.append('
    • ' + file.name + '
    • '); }); target.listview('refresh'); }) .bind('fileuploadsend', function (e, data) { // Update the progress bar. Note: for some weird reason, the // "fileuploadprogressall" does not work under Firefox. var progress = parseInt(currentUpload / totalUploads * 100, 10); currentUpload += 1; $('#progress .label').text('Uploading: ' + progress + '%'); $('#progress .bar') .css('width', progress + '%') .css('background-color', 'green'); }); }); $('#upload').live('pageshow', function() { $('#fileupload').fileupload('enable'); }); $('#upload').live('pagehide', function() { $('#fileupload').fileupload('disable'); }); $('#upload-button').live('click', function() { var pu = pendingUploads; pendingUploads = []; $('.pending-file').remove(); $('#upload-list').listview('refresh'); $('#progress .bar').css('width', '0%'); $('#progress .label').text(''); currentUpload = 1; totalUploads = pu.length + 1; if (pu.length > 0) { $('#upload-button').addClass('ui-disabled'); //$('#upload-abort').removeClass('ui-disabled'); } for (var i = 0; i < pu.length; i++) { pu[i].submit(); } }); $('#upload-clear').live('click', function() { pendingUploads = []; $('.pending-file').remove(); $('#upload-list').listview('refresh'); }); /*$('#upload-abort').live('click', function() { $('#fileupload').fileupload().abort(); });*/ Orthanc-0.7.2/OrthancExplorer/images/unsupported.png0000644000000000000000000004237312237177136020750 0ustar 00000000000000PNG  IHDRS}$gAMAOX2tEXtSoftwareAdobe ImageReadyqe<DIDATxwt\_Fif4iԋ"Flz`LO @(I$1ƽ^nYer1RHhi$S{_ uחCYF3g9>{?A3 lE k`0핊JatM]W_g\~ywߺgo;'otϾ̶9W}|o67gyͦYf-3L?7]ys|KMYfk_sqŝ?0{sy[usl'n{uW̹ywnv\|IWims6[kf]aƙM5sy wώ0ŶS.V 7Ѧg:2L[bwm3Ԍ҂q * XI:6>XQ`G*WĹR)6h2v2ziO0e.Y# ٰ`yQcI_9QIGeɨVE{0`=TJߘl@z =}Pֱk3>%5saD5|G5,_| aqV/)1:O6 C)CcXk3ZxcrZKCBrcI<6W%1kҳz2>w ,FDMH6mS& ɰ 7xY7--uM?!HE{no#7jNI_^L4`㪒R`l&l `uBr_e 159tgo7_mZa21"~Vli?؂1\0R1^>!)ؒQYL呮o/2%yԁAFy ]k B\9@`+S䌚1= `sb2&?1]OX_Eê°gdD{n.\px BZF| (e9 lEUjo,h,`D(&v WYJh-asp_;x/}_x?^{>{>~q_ܾߣ/~ߗ>O%鹻727U+Sm]BD՞9yB<є:y(RF8lɧfIhl9-^2enCh@^BUKBji"V+~9V*Gr~N3xsD':`e mu[MG?K[Ω癖c<qǔss^fntqم_;$S?zz_ mgN1\wڙ)F'‹ypc(S3|)$9zukSM'>lPo=Wk)ۦd/YbP*XH2w쑗}E0&2E1ux.لO4,a6+ƫt %R0(LxmJqbOy}Y>Av`[]wAkJTHV/x/e@w:C_f RǏ|sCxnèp6pw&N 1zA"k`8-b ߯`Mw>W_{a͖aZW7":K'#H#bh/'QRJ"9K)%s؉3OSinZ7HEAf#Ĩœ=a#a*q O,%?s |jcjYޟ(ʀZ69p;gH]:pg,!g)x"Fν>>iK-^ƒOzwTw}#<y_Fl wqHv֧c w,$;@[<8qNX%<.Ζ1CƢ Q.rX^] r]G&,j`,>/ ! p?XӇWlrZ SJ$#CL0jvrW"&fi2t<~%<2(d X|Ks p%-*RJ:akE]]r$0a)]q OƽQT A5|H`?J[GŀFX͓`&ϻ hAu I9˅:ꚔGr|Oi⹖Py 'V0њ[S#>VC*P SGLM|G{6lNJƃpV^ oQD;5umfK%Yl=Ka k؉:" ~%L#r;P@S[CȺ2/L(uY59(((.+SN!a"txML\6"q YxEB TP> 4)4グ/BW"/ژtW(o$+;A1y/Ѷg6 } tt9XȖC:`Xݰ`l1qDŽU?[OpP/**k̤Sz)cQ=b M!ުTgS&k| $Dc&$7X`ۻlq-H&dx|!{kZ/.X=1pTRo/r}uHՈa&KUJsOp-+p-oߊ b-(w  sayn7'2Ux5 <4cS=PSV9Hdmo!a~kkדL`'$+uLS2OzB*Bf?>*ep7o^QVUF..8w1]QpZ +bV˅wpzOL( T~SR}.2 0:|T2gd"ʆЧ۬Z,:Vp>RApԍWXΌx$3?twF\f22\ֹj)EQ^AFPT+{bƝpƒwy <>О(\΋ v\i>Fp09¯^`L"<4Mc_\k'<(ohe:oyP7Ƅ91!]١^ƍ^4*}-` gd YXcRʻjz g$\~.(zO3x3`ķ s4=b HUo3 n,t\FEpIDŠ[}Ƴdڡc 1wI' inQu4PV! ‹+Ԩ)13R'0» s YȅUj?fqVҙ0?ʛ(ڸۍ #A[j[krJpyZ?=e YCX8V"em++ lĹoe4Agv؈8PaEY)ᓂh?3&$x0{SH7f=Re%PL1 XFn YnX}Db9ikmXuVŻǼ')o3 =.J-,Po\Q ;iښu iR].Q1<;f%kPq cVL^B¨=uaQ9!3Qj>MY|ɋ GvWD{SEpOʎk}Cs,yޝPA ~RN@aJ5G^B'O:mKS5D*kve)KTnvs6P2ҵdy%yNpbXg>E?򑆇p^©m4 4^IhdX`><~kXRN굧N<11GbL'pG׍\o% S>t_q>N0mx2KvBfj,&"&2"B"ׄIé%pM#\߆Ri'_5z7@ߦL(y/| bCs.` da c; +AMTF9:Y*aaP8y KKvCCqTgõSȮD^H[{Ò>[ O7  - ּRl׊*q;RЊc~7 D{us ”@: q*t)LhUJݡWy\ŐkX]YOAX-ڱQWuK]'d\%d11YAh`,Uψ*eCWZ3sp£A73BǡhȰg`C5C9K+r)Zj۹!TXئ]ksM V{{= b-kBn-I6>Pmy&m"j K/}+$tO6uED>RMϟu R 9`!rm^1x`1:"r:XZS]E(&Ѝ2V q(Aa=+x X]!Ah">Q3=:w):1dfX\nTZs܉&IȗK _u<L[zsS: :kN1ԒxSy2[{L7 oKSxTqmX\903-yE,NL'J(҆dHmd[P6٬GYHcwd 0oT Dap}l{f tccݝia~A^.K)ra)RbI Ui;3)դ CY| 4'R ! =W'EYO2@f*abu5D9-kjKT%UFhOK:s<R|NnR´B bo}Rʷ('-ќ6u)q$7B>l`  Doe\ ?aD/Sc]>SJʆ~>v8Kj"JNᘶ5}3`Jlk E86n}xscPkc ,%OB]EFV2p6 Tʀ|8j,C5̆ KY ށXيrc!Jj~;uh0QHҝ;τ,"R^\'3"wtC9Sp#-x[Iх ]]2UqxvtX(>CXf1#uP~߸㝺 cd04u1H34_"^VxRgЭ{vf;Kɢ*Xsxbv%7$n.a|}pj[`!IةcZt6C%Ci&l,rE;3VXcP]hAX L)]=\u׈ko#[~)> 0ѹhc€ye\Q>B"pS[e#aUnђ1 BĤі}:Xpc}6}K;hѪ BBkT1[R You𩶄$ڿi9b!\sZ_8O%b#"83 y'{T#T4#=Ely\mv1sI$1=Ӧ?je[7h` a"XD|8 55s Ѐe$doŠK荋P0[.4C7B4LtOl<a&Opujf\"hd K.Bv)8fBjv"] i "L+Y(!2< BS쿼RXpB%CdljHU=PIrDR.k}#Y_j$gRSDRg +!d-OBU )x-"l˭1Y.{8/ >y&Ú/q:`,$CFېjn< t bduRuݩ0>R~,]0Y+<᪦Z󆔈0 U(%G|*Ml,FG$X*zRxk)Wo?Ekb]*č5I!YȨZB @ى0Cs%.Cn|!ZF9+ÒR/^bSUjgZaUF5Mn%wm{0-T&[ЕzJA'< FM`Lrq.2\%K jp~0UL(Ө/SR)$`.`&"mY5a YEf^y$Dj wAFK'4B}ב~1m8yDʠ$ު9U\mYX.+W p&A|-8ϏJl}o6w0w8YCc.?u\_9zGiXwunjP6ݰ½Pn1r-u@|$iN"էZUB: ,.`r aq_1O+PWpr?r^=cp]Prlj D`|! 0QI dqy ֬E+uc_{bGA:ahv&棒P}Ffc܋xM*%0xnjÛ<6j.5i|P{$ ̩kk:O;̕Q)! >"ׅT'2ܶC>˚9*yx$-O(e]djdJyH#F!C: )H~H`MHlpzI*aK"(;Űx/lR[7'GO~:cZIfŹImgJI8/5,:}aqxdUF=ϑ^K%ϐhO/evN5ԖIJPgh5@%KgEp4I+C]7DOdR N%$Ꮏ׀bSS\wɰ7Ջ`+O̡ ݕ4R._:&5J>+.2,a٦,7 50rEg>m3nvƔAgcvMa&a:c̘ezM} eo^bv3kuO7/yh82u7)S͆ av ].6Os/0]-gs7g/nld'c;,3^d=Of,s7MI(sm:s5gg8lf3}o3~%mUBʵX]zܱw*| g k,BA'SfV=h!Q'8 1oɕÊ_DQ-F2NW&'4wV;c3] TVRS:l4Br_iC?rhIa)qKj:@C7E7Gyw ,dc.(4f cɿMUE[G_b<&mFGҸըcG*e )T}3YuL܍ O[ orɝ6W> F2^e3Bx+w .knUrY^ \?v. SNwI^,ŀć{4~ N7yqedl+;ۆ1/>y:Xe4kض&+=2: o*TTp6xxUxǮDzV]Q3ZwqO5M"z{Q|W`\ K [J,m`dVO1#[E7`=tVo k\˜Qds_d!h=Be c*LGs=-Q#*Sܝ,,Ly3>OSX,#]o牧e9C(PaPLy@ZI lszRq$ s[uҳ#{gWy>UNE4n$<&#Rx k9ddKո]\.RҁgyޠW.FvaΔ2J39G-K&Rp /}5*`<+h, %P@%yο<ZDXDN(NG@9:FqFڦ# ?TB9ULQ=b# []J5J a{ ~6$ p*cO! ɒBanyH#vPWŽ۹,ld7rXxt %9`X \w`*"^=,#U*)]2Z(Yo-xyq (dkxN4_8 !DF^4DsB ΰBXWr,me_e?琌*Zt^ 6vlfy+M$=jPS#u7*1ǬMY[C).+i| ,j];j[ǥLI5+a{:"!e*0ֿȰ֍fHPwUDv ݑo3hʛ1.:y{JKh|惎dy;11ƶ,l(Ѓ/2,L,HKM$zU!Wl4\,%,}f<>u6ڭ60ổvQj.Ul9ظJ!8Y{:hxPEU\esRU_[5]ICOxYPW}PSj :z I].RUFagQQcZSORa`cRsEC9ZoUT+?3o d'i Ulٔ?f[FƶriK]mflmCVFA復7\XL lX/>jS2:3UjJ8O' s=&,3a'<x"EH^V[X<=ηIW2R KWH#rfBP6Sz[C9j+Ʉ *[ ^ZAt aiSܥts &Kft5,R$)$}0ܰ¼WA4*W6F17BS27x#|FOETBXwz NMW%(GM)7p3(#;BR= e)wrjyד4O0~զ"*ah&gP ;'?$}Eڢ⢄LBzm]OImPe\6cw)m1?V{mwm̒wEuw]-{l}w?aT˚}fm zizaIߜ+Ͷk3l;d3.~ywur+4c/[hotԻ;8u죗{M3߶ma lۀa l5m SpA;IENDB`Orthanc-0.7.2/OrthancExplorer/libs/date.js0000644000000000000000000006232112237177136016604 0ustar 00000000000000/** * Version: 1.0 Alpha-1 * Build Date: 13-Nov-2007 * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved. * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/ */ Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}}; Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;idate)?1:(this=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;} var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);} if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);} if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);} if(x.hour||x.hours){this.addHours(x.hour||x.hours);} if(x.month||x.months){this.addMonths(x.month||x.months);} if(x.year||x.years){this.addYears(x.year||x.years);} if(x.day||x.days){this.addDays(x.day||x.days);} return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(valuemax){throw new RangeError(value+" is not a valid value for "+name+".");} return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;} if(!x.second&&x.second!==0){x.second=-1;} if(!x.minute&&x.minute!==0){x.minute=-1;} if(!x.hour&&x.hour!==0){x.hour=-1;} if(!x.day&&x.day!==0){x.day=-1;} if(!x.month&&x.month!==0){x.month=-1;} if(!x.year&&x.year!==0){x.year=-1;} if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());} if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());} if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());} if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());} if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());} if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());} if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());} if(x.timezone){this.setTimezone(x.timezone);} if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);} return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;} var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}} return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();}; Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;} return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;} if(!last&&q[1].length===0){last=true;} if(!last){var qx=[];for(var j=0;j0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}} if(rx[1].length1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];} if(args){for(var i=0,px=args.shift();i2)?n:(n+(((n+2000)Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");} var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});} return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;} for(var i=0;iDAh:y `:hl TGA%_3;.jp@ d[Hx!#hi*zgCUwC3 C72l.B2.()"!" ɿҞt{u #8R ,`A|7ܼ`@qB:,8P(HС?*"2#vlł r,HE1j;' ! fOE#! ,..I+x8km[(b_Yhi+5*` ٧(hQ0V Q-wxP6OwL0\ C <#~"I6 C_#7 ;7{7..-(Ø)H(M ֲvسXh!x x$H 8J>D@T `…i5ˆX@_ĎAFS*ab͎U PjNF;8Js%! ,..I+x8km[(b_Yhi+5*`  JPA`-HaFԩ!A%C`3:V,.:]S6K[Bo!7"s?uڒEP>kD&Ȧ=BmM#! ,..I+x8km[(b_Yhi+5)'P0 ٧ ƂTzP@PȅN uAih0: c D;{$O uAR{q46"  oY !~" 3}/# 87 <" < 3<28<<Q]7  ,TPÁ1TQŌDkqpBt, @ȑ+YAqe2> K Zc&¦Bo*PV}(i! ,..I+x8km[(b_Yhi+5)+ a8D$d"DhF J `*b,f .vqF3C>'# tv hzmp!Xt # ` -! 3 ~/#88<<<;<<; 3.2- @ S?8Pw @| M@ŏB)#JGF+)7$r=s93 :بnkNFUHF!,..I+x8km[(b_Yhi+5)/bHL>-0$O5`=RTue`Zk(l^dC(6'# fXvvA\{|p!t# ^mo).|-3 *<27 <;8;ԩر.-# "C> 6C@ {l*0 EiHТC92jx ErqGW:)ʑ2y$8O|0Րmh$dFsLʒSGF! ,..I8ͻ`(dih1$0W <]=!$ \c`8&& `(;)8Lu}r9 :p,C{>V%{ V"jKN-! ,..I+x8km[(b_Yhi+5;FA}v@!qP,Z_p`*NTZ .`ZUtBKx#u> *6x" tv(/) ;2  873 2.-(#˫! ˘!צ47 vZ`&h#J@"E~ ۸"1ŏ::0aˤ&Q( 2 8 `8эF̤掦@! ,..I+x8km[(b_Yhi+5?G!cb@u(cP,lVM$1($+DQr D\egxyzr~ f *! 3y- .- )( #! !Ɣ̍ߢ|.(ބ"|}!#J$v/ @"E5tz>CbLX`##"8hUeE8I@‹q !ti#NJt(! ,..I+x8km[(b_Yhi+5Alb 5Juzb tD>t`p%ޫAV(#v'ު'*r ~ 2 ) x()( #" <7 <<22#ߠ2 9#"!̝ѣ!0p`';6ୃ 3* ŊC3$$ǎepr@I}'7S#&O.H )g ` rVy"%,d<!,..I+x8km[(b_Yhi+5$u#uB6R b[(Ø.`К5{w ]G t}(y # ! ;B 2B.7 . <37̿" ( 4#)9#  b#D 85,"x ĈEYȍ@Ž?$0{ء3&GRI3AZ21%9]Ti>5^R U"@A5! ,..I8ͻ`(dihlOr-1?@ IP@ˑGZ(;!7qْFhd"NVB! ,..I+x8km[(b_Yhi+5$uC R\%N-dD pF- t:e6*S@G|{\Q3{q<; ]?3~< 3B3 < 3 k; 7Ǚ3 Ϳ#S ) !XT(  "  ɓW6&̇ (HE*Dʼn C Lhbƍ5w⼒0@af"Hl0<'?=tܩ SQ~D"擪>]<!,..I+x8km[(b_Yhi+5$uC !@ t&# T[zh+@3M: -T0%[||n(~((m# "w?3< 3; 3Z< ƿ73#q - W#  ! $0G!Xp?V22l`("CQH򢁌vx"0MԸ"H0 bDɯE< \4HS `DS,`D"H?2! ,..I8ͻ`(dihU~J]288^ĊQ` j2J[tq`20:N#A D{H}H"!o~^ "x #r x. % (ƶ̾ 4 :Ia4! ,..I+x8km[(b_Yhi+5*/i% m;i`6'(lR%x V&'3X BLLk wlB|}" #w) wf-m{)("#!!qzu]~Ͼײ-3##2t # -s!G!H`A 0ȧ0;@q 2tpC bB8Z`"E Dr /I Z;`~rv"ɐ>ֈ;Orthanc-0.7.2/OrthancExplorer/libs/images/ajax-loader.png0000644000000000000000000000052412237177136021470 0ustar 00000000000000PNG  IHDR##{IDATx^am0 QP0PPPR(P >k?>T/ eĿ WS ~ ^ hف2;a!!bdB"MUQ!>:€ :LjfSz}!x.H#2v$TZ.IENDB`Orthanc-0.7.2/OrthancExplorer/libs/images/ajax-loader2.gif0000644000000000000000000000132312237177136021531 0ustar 00000000000000GIF89a ...```"""JJJddd&&&NNN888򶶶! NETSCAPE2.0!Created with ajaxload.info! , - di @85p{۸@ .s EB! , $`a`i©ҧX/(;! , 6 a,$ " cb(ϴ2[KӸNU *N! , 5 ET4b$I<uy; Ȅ>bG̑s9y֋*R!! , 2 diֲXDQHbRUEɴ]:^f_Q#cJ! , 7 di$q]biمah㢶m] a.M$4_-66ˠR! , / diDQr%R 5p Ěq^-4CY! , / diDQr%R 5p Ěq^-4CY;Orthanc-0.7.2/OrthancExplorer/libs/images/icons-18-black.png0000644000000000000000000000334712237177136021722 0ustar 00000000000000PNG  IHDRU1IDATx^!J @_f|jhH XRqJ?EE~Ję;jV|GZY+&qvp@&dq1ʮd2 ]:KH哞LD0l*X$h_u #z| ,$Sc!8 8wjG)p! ( ؝^ 5u\i0 QAIW=faaΜ0@h1)w#ftb5=)"X]A<Xhᠧ „50zmLDcmxS>|?f]^b |袭B*BUfE$x9B'uYeAHF1c 8V&ervjUЇ،&ić! 0@}{_2TQ8sU~ E *B|;9(0HM6$x)ڡpp +"-=8hcw`!$"B%2~kFbԀ4>uڧJxL h;}*:ԱlIn45 3|蚰P꨿vPԅ-V8A҄xI5Y/ /nZu 81*i8q˺ERCXhyZyUFrMw#o./RG+:6U(%f n4e¾4ua7sW-TU>tMXŃ)%*@"!N|gV;M]B2d[&9a1*"gj\t[Qai$ZD"5x9`ԓm^|ב| d!(@\U\o<*{\X[.x |7rWt.YsY> 3; zEKtzfqi0L:LyWP OqIW{{>I4R*G͌6qDë(#%£QG'Ed֘7pe4#`])2AL-CbB, 5 a>RVDna㾏Vt@x6{Ȩ l\yF..Ͳ[jyd0=eU$⠍Zyrbc4mJ&BX,Q'Na=ZXu56LyY"X3*&m_UE.7F!ZzC D>ϣ^{9AHpsV5:l(5 ,u*B.I CCTN:+FD584w4$/><2De/qLO7|@0S/4 XF,O5胛i`tp@p  X/ 4t.tӗ'2|蚰"Kbsy]!;11SzY"Jd<("B$ w 5801W"8x%6Sd2'DP|#U>tMXl^:,$d2̛LGHps >L&y7nVGDiYӧHeIENDB`Orthanc-0.7.2/OrthancExplorer/libs/images/icons-18-white.png0000644000000000000000000000341612237177136021763 0ustar 00000000000000PNG  IHDRU1IDATx^휡o:\Å1 Vx2)#>`PZ, ,ދ]\6YOtNF:eWʧٜw~3NGYYYYYBl"-%bĂ` _YYPPx쳲 BKp?ݢ4FXx )h+zq&·&`iЃu_h6c@o.@9<|.|\A ;!:0rʃj!+xPIgP{ 0' Fw~b@E<[(_lKn'j纠.Q(,&O=2|RG.7XEKuuf.̜>>zLh\V#p~_0!/JeO,$a[QbF^BZ!ʢfOPaulQ!•iiCԭK_B(*`L'$ 5>l‘Es#Cȩf`R`0ij`K 7g$: @vjA;<0:|_95N@c&|5,0ԩk(2MG:+qU>r)f䲠B>P+}E(xH!hY?"*aۈ]G4'B'CC\TzFhzrLRwarY^_ 7ݝL“ů2AOe3V8`%1^PPM]C pz0:Rb\u܈2ү8@(Xs1>hevZߢO q95$1MPDΤ(dT,^:C:vڃBNeFk= O<'SWa{Xv߶Tv M h\>T;b}b|gB0!vb_JwA{."10py*&~ @ja.{@2\n@H\=5PWc:\3(B}xE ~ "hH87==2S1X$ңW6#a%l旝(||a(̔`ªҀph[DU%ƒwJr@7-f7;o; j^w`#f](0&u?NgCOu{TBc~zrw tP-׫'($+*ChuE$CU>r),hUQwߦ #bxΜi4%=s$V1a1Bmyr >rT[FM( ,lj@@hO^ BH A7H$;9 ǎtB8݁~}rFZl5DIk!,OC?=aEvPN*'F2 _p6фp#n4`}t"yCK6SQ!JUC\~\D?GRI(,h 8$樈nvBԓA<>o]O 1Aɽ!Vȥ}zI粽OVVVVֳne!}^ٓ>YYYYY/xr{Bp{}uIENDB`Orthanc-0.7.2/OrthancExplorer/libs/images/icons-36-black.png0000644000000000000000000000703312237177136021716 0ustar 00000000000000PNG  IHDR $6t IDATx^/oJ^xfYhYY$%O J  KEa,t`ڹcg|v=xΑk+hyvmJ$D"H$D"H$D"K j <"H$D"iԌJG$D"H$ih6 D"H$7hӚQ iN[VVcyX$D2H$00Co kŀ]D"Q}t( LPXP(lK"ilGmcxC`@A.Beg "gIA%DI04 " x$ *h #%䠂\pj'Cpbi/JAk DJ(`L>?uꍮ#`G h0kM@T6GeA42*rp Si4+P9`e\:ݹvjfB=98k惁HC櫒 ˭KaA0hG9z`?ODD&bł,Y߼K2-pO {EP @`7W 2A;Hmfo6P5 炁Hަ9j8aZo Aw.xgx Mual #*HA U ḒxI<$,y+ooEcBkDo^|z` 85pH1L ̄]9I^&Y2hQ oZ#W2$85e0&TR ҽ,I0XN9 ԙz߸o L\u`L3ۋ E=?wy^x```qͫkP4 ҏشL%6hcl_v)veX?)1۲DW"`@13'89Ɲ B6X0A2_FU5#>2`߳>&=U!,G ̤xm'Б$"}<2"P#n,@e2yJ {"F1dK vh{{ǟ4R4tƌyق pZhV N),īAzθts?6+am^.jk9Ryfx:6Yogj֬S*8%h%hi#}olg}Auo1S 9zK`*@i$em*ت4$[9 vf'jjH֚;s ~?e@?Gm|~Z2l/ ʼ}NQi,s=1!.:̡ ĂN 4Jbb^t|oz]vJ֜3c]oBHDрw[ Y:}Ns O(F^YH ŏAvbB`X <D;w<߳]7ֺcUX6x,`1yCq :ixײVA)DSj@!a$CCu. ɕCDR1ˮڨ8 )opfQ vY{ Ѡ} t̏g\(ͯݹ +v.n9YF< URELJ,g Qق mTd|[(2\K-0   X[i)XdK0,#  +ޚ .̺M0hV(} Y8?&["MB] v(βL3 ix08 0/9TǼV 0(FP 68r7)<h-1,52UCE1^"9kq$`X#\` G>aQ0;s$txJ޳2cA0~ > >y Xtn%`Vk-ؙx ^™ _85%Hٶ!رup yVAoⲋ±S BcT7N1 JOP&n0h`Ϣ&"ˈ<l k-&򛱟cC  `<3<Dô"MF _=%,#@Y(' =*{8?qnZ_4>"( n&0g=eDgc&%fSzDݼX;d0XtZPg\3?50r"-9'`~4jgv뿆IHef'7'%`"YOQ+XW*-َ)`P@2&K87Aet$ 3]|_,vq;/t/K/@Tfw8拄_832P2M `XLbE8 `CA"I q)IM͎,Ӳon4`@"^l!l ~+֦>gCy]qXU,K{5 DѠy{THח h TZVhjLG ±? +`wp[1A&`@"e*h` =t 4ǻ FFטe<7 "dS|0pT$n4"$wUdfƸ4h0($`x(PUA2ߴf@N2G.եFmGXp9fd^xo.]eGYO ߘ`@:io/q14A>O4HHǗQw(+8;\I^R)sMf’[ Ѓ%E_l :4V_mAtvs3Ă8/X:<#3Ut"L⛂E$.xD$Dnz|+/qp'X; CnyiD"(?jD"ѕ <6/GՒif{uňM ?yySD"H$ / m=1]z(xi n4<"H$D"w+Οf>hD~g#D"H$=`P4xߧ7)G$D"H$J'=ǷV1 EZ?/DkM?<"H$D"QͭMȷ*4_!_@D"H$Q7G<>oIENDB`Orthanc-0.7.2/OrthancExplorer/libs/images/icons-36-white.png0000644000000000000000000000710012237177136021755 0ustar 00000000000000PNG  IHDR $6tIDATx^!sH @C3f sPЫRP*P8L>hgY:\OWeM.     X6FYvGAA-P g߹qN$̃FjШBUjX 5BZdiA*j7ms*TœQCjA/j#,G振LIPrWOm l-Ut2bз1p_ٛ e`)U$#5!bD @AB3OKQcbւ @#jF$մ@#A*.4)d6Z`V43HoԉhQ~cxdAh <|1*AJr҃, Zeb1Z ZLWguJbzѦЩdDx~eEr&$gL"ψ-祤} Oh8K .եE~mawq u/}jlfǢb@u"Vs׶TřWYb jg/*%6-haɧaQgy(ve#mW)b3@+^CjD тa Ex2"o2؛?Y (H U W7V(TD fZ|`k;)#5Mkr(sijįpװȐb8l-[6E;vN4hW ,)-аȒj[Ф=bU1fZFD=qe-]dХW$vK3#o C’"ZmЬSF A k7 *Rfl|5zd$ki)k#ecɅM*J8£C qH iU3 k͝ԕb,@}6*>T}7O%A2/Nb˾f.ey1g&!ZCXMðѐlsjĚqcrɅA=BhHub@jDߠ(!^ V=SUv+-%VzmWk~;-PKf3#cA7_.Ԧy掲Y"qwF Qx Di1E*5-`qG\ F0h:8=5Qr4JJ18&ۢ1M͐Ipto1ĝFܹSA1sCt|>0(ihQ ZɛX{NkvoK_m0ZALp>YAeW\v^i ,>3Hf\*vh6.Y2b<:b ?DDˈlA >j3,& ChD`hCGؚ2(A< h"Y/Q~uEۑI:E !ʕ2ero{-0ǡfv,yCmBu5hZD,Ϭ%Т`jA2uv卞{$t (BDDNHMC ~¡NGT1ׄnykbJbv%1-)R=˼kzԧ#5z9z_ʌ |!=> MzE.%A`OPo 4m--?Br KA>'> aK@AU:A};jlfR Zp?h^l>ow#  БA܊=0І7j@  w+Ο|5Hԅ %~ւ󙎷#  l1H?@=oo6M#ւAAg>9qf>PЏNՏ35AAAz0{Wg*l'}hKJ :R   PP'CAYոIENDB`Orthanc-0.7.2/OrthancExplorer/libs/jqm.page.params.js0000644000000000000000000001023512237177136020650 0ustar 00000000000000// jqm.page.params.js - version 0.1 // Copyright (c) 2011, Kin Blas // 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 the 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 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. (function( $, window, undefined ) { // Given a query string, convert all the name/value pairs // into a property/value object. If a name appears more than // once in a query string, the value is automatically turned // into an array. function queryStringToObject( qstr ) { var result = {}, nvPairs = ( ( qstr || "" ).replace( /^\?/, "" ).split( /&/ ) ), i, pair, n, v; for ( i = 0; i < nvPairs.length; i++ ) { var pstr = nvPairs[ i ]; if ( pstr ) { pair = pstr.split( /=/ ); n = pair[ 0 ]; v = pair[ 1 ]; if ( result[ n ] === undefined ) { result[ n ] = v; } else { if ( typeof result[ n ] !== "object" ) { result[ n ] = [ result[ n ] ]; } result[ n ].push( v ); } } } return result; } // The idea here is to listen for any pagebeforechange notifications from // jQuery Mobile, and then muck with the toPage and options so that query // params can be passed to embedded/internal pages. So for example, if a // changePage() request for a URL like: // // http://mycompany.com/myapp/#page-1?foo=1&bar=2 // // is made, the page that will actually get shown is: // // http://mycompany.com/myapp/#page-1 // // The browser's location will still be updated to show the original URL. // The query params for the embedded page are also added as a property/value // object on the options object. You can access it from your page notifications // via data.options.pageData. $( document ).bind( "pagebeforechange", function( e, data ) { // We only want to handle the case where we are being asked // to go to a page by URL, and only if that URL is referring // to an internal page by id. if ( typeof data.toPage === "string" ) { var u = $.mobile.path.parseUrl( data.toPage ); if ( $.mobile.path.isEmbeddedPage( u ) ) { // The request is for an internal page, if the hash // contains query (search) params, strip them off the // toPage URL and then set options.dataUrl appropriately // so the location.hash shows the originally requested URL // that hash the query params in the hash. var u2 = $.mobile.path.parseUrl( u.hash.replace( /^#/, "" ) ); if ( u2.search ) { if ( !data.options.dataUrl ) { data.options.dataUrl = data.toPage; } data.options.pageData = queryStringToObject( u2.search ); data.toPage = u.hrefNoHash + "#" + u2.pathname; } } } }); })( jQuery, window ); // http://stackoverflow.com/a/8295488 $(document).bind("pagebeforechange", function( event, data ) { $.mobile.pageData = (data && data.options && data.options.pageData) ? data.options.pageData : {}; $.mobile.pageData.active = data.toPage[0].id; }); Orthanc-0.7.2/OrthancExplorer/libs/jqtree-icons.png0000644000000000000000000000065012237177136020437 0ustar 00000000000000PNG  IHDRaoIDATxڥnA1i\x&Ed]jD:&JM[D"R<]H\B~E:+A«%HNvx YϽ^t6,,v1b-c;ܱ%к_dnd} <6B1L&n?jI{~Gwx?׵oyrc4>׺kcLxSŗz.Ieq%t:eY.4CeGNs@+P6@_A]^Cz0jQ(u<;ZSǬo7]`?ݮ &0%I,nm"4]ԿQS-VIENDB`Orthanc-0.7.2/OrthancExplorer/libs/jqtree.css0000644000000000000000000000473612237177136017343 0ustar 00000000000000ul.tree { margin-left: 12px; } ul.tree, ul.tree ul { list-style: none outside; margin-bottom: 0; padding: 0; } ul.tree ul { display: block; margin-left: 12px; margin-right: 0; } ul.tree li.closed > ul { display: none; } ul.tree li { clear: both; } ul.tree .toggler { background-image: url(jqtree-icons.png); background-repeat: no-repeat; background-position: -8px 0; width: 8px; height: 8px; display: block; position: absolute; left: -12px; top: 30%; text-indent: -9999px; border-bottom: none; } ul.tree div { cursor: pointer; } ul.tree .title { color: #1C4257; vertical-align: middle; } ul.tree li.folder { margin-bottom: 4px; } ul.tree li.folder.closed { margin-bottom: 1px; } ul.tree li.folder .title { margin-left: 0; } ul.tree .toggler.closed { background-position: 0 0; } span.tree-dragging { color: #fff; background: #000; opacity: 0.6; cursor: pointer; padding: 2px 8px; } ul.tree li.ghost { position: relative; z-index: 10; margin-right: 10px; } ul.tree li.ghost span { display: block; } ul.tree li.ghost span.circle { background-image: url(jqtree-icons.png); background-repeat: no-repeat; background-position: 0 -8px; height: 8px; width: 8px; position: absolute; top: -4px; left: 2px; } ul.tree li.ghost span.line { background-color: #0000ff; height: 2px; padding: 0; position: absolute; top: -1px; left: 10px; width: 100%; } ul.tree li.ghost.inside { margin-left: 48px; } ul.tree span.tree-hit { position: absolute; display: block; } ul.tree span.border { position: absolute; display: block; left: -2px; top: 0; border: solid 2px #0000ff; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; margin: 0; } ul.tree div { width: 100%; /* todo: why is this in here? */ *width: auto; /* ie7 fix; issue 41 */ position: relative; } ul.tree li.selected > div, ul.tree li.selected > div:hover { background-color: #97BDD6; background: -webkit-gradient(linear, left top, left bottom, from(#BEE0F5), to(#89AFCA)); background: -moz-linear-gradient(top, #BEE0F5, #89AFCA); background: -ms-linear-gradient(top, #BEE0F5, #89AFCA); background: -o-linear-gradient(top, #BEE0F5, #89AFCA); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); } ul.tree .moving > div .title { outline: dashed 1px #0000ff; } Orthanc-0.7.2/OrthancExplorer/libs/jquery-1.7.2.min.js0000644000000000000000000027117012237177136020437 0ustar 00000000000000/*! jQuery v1.7.2 jquery.com | jquery.org/license */ (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
      a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="
      "+""+"
      ",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="
      t
      ",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
      ",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

      ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
      ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
      ","
      "]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f .clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
      ").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/css/jquery.fileupload-ui.css0000644000000000000000000000300412237177136026417 0ustar 00000000000000@charset 'UTF-8'; /* * jQuery File Upload UI Plugin CSS 6.3 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ .fileinput-button { position: relative; overflow: hidden; float: left; margin-right: 4px; } .fileinput-button input { position: absolute; top: 0; right: 0; margin: 0; border: solid transparent; border-width: 0 0 100px 200px; opacity: 0; filter: alpha(opacity=0); -moz-transform: translate(-300px, 0) scale(4); direction: ltr; cursor: pointer; } .fileupload-buttonbar .btn, .fileupload-buttonbar .toggle { margin-bottom: 5px; } .files .progress { width: 200px; } .progress-animated .bar { background: url(../img/progressbar.gif) !important; filter: none; } .fileupload-loading { position: absolute; left: 50%; width: 128px; height: 128px; background: url(../img/loading.gif) center no-repeat; display: none; } .fileupload-processing .fileupload-loading { display: block; } /* Fix for IE 6: */ *html .fileinput-button { line-height: 22px; margin: 1px -3px 0 0; } /* Fix for IE 7: */ *+html .fileinput-button { margin: 1px 0 0 0; } @media (max-width: 480px) { .files .btn span { display: none; } .files .preview * { width: 40px; } .files .name * { width: 80px; display: inline-block; word-wrap: break-word; } .files .progress { width: 20px; } .files .delete { width: 60px; } } Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/css/style.css0000644000000000000000000000044312237177136023506 0ustar 00000000000000@charset 'UTF-8'; /* * jQuery File Upload Plugin CSS Example 1.0 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ body{ padding-top: 60px; } Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/img/loading.gif0000644000000000000000000000747112237177136023734 0ustar 00000000000000GIF89aݻ!! NETSCAPE2.0,||H0*8ͻ_dibaxl+.\x>ڗpHTG`0I a2KϏTJXlgjם J3GisߓCxzMskS0pz)vq}y/_` (hǤʨAѽ{ ˷ȗx+7ln'+Zd:hb?vpȐƔf2,ebņU( h!ʔ*l% fafLXghGC 3#;^L8u4P,KYѥ;q]˶۷pʝKݻxB4_a' hqV#*Me9fYϠCMӨSArSe1~s8P$&a2Uuwn]Qq:1?OXzt6s]%vZ|v̸RzkdyG/~_IaWt>P3gۀ- Aha|Q!~a!5䀈%&Ƞ!1Jbxأ#+)#2y$ƥ5x~H`"[ 4aRNY&Xx:NvTr&of&q(s9Q}iuVhji֨{'$!, W0H0@8=+`(J7(WViv+7gm<#PH@k8DG$N=CYi+^EaAi-n.{!vx/*oxyd~3{|8t<$  @ 0%= KG z2c\3 mYse!rj&K !, NW0HI8ȵǍRh!9lK+:`m<ǽq,MڜR6 xdv}>LƝϗZui%^qN.|exV\VKOFBA83›ʳ͑у{ڷ c|!ܿ& &ocWD=~mPI`! jDmE+ / ɨǎ8>!r&<!,<BBHI]Ս\hd*@+O:xpH,Ȥrl:ШtJ= ՚7/. m:>;|w;FzEt?DmAx@WC RPO!NM'KLDZJº,˶I׫HFީG;E7D3@?o& H``@oQxaCt10K!,0WH ,Ik{Ma)ZѤ}.vE4 {_&zxL.ϡzn۶|vs~7z{vtqohhfc`_]YVS\2.6>ͱ:ҷBba`cwf! ,||H0I8ͻ`(dihlp,t @8^H}$T:sJX+N^N1]t;c)y%Cq@09>C4 I19}Nm`>a IuL IFvLC!,0vItkc\8 !i\–KoܕSO>c)y%Cq@09>C4 I19}Nm`>a IuL LIvCu!,0wI[=c\8 !i\šKoܕSO>c)y%Cq@09>C4 I19}Nm`>ݎLuL FICI !,0vI[=c\8 !i\šKoܕSO>c)y%Cq@09>C4 I19}Ntt0OLL }CI|?FI !,0}Iݺ4ܘ 5dh>X[™+H޽D!iCvb e"NK%WD<}Fv]`u0hxNH NHE!,0t)Z4k`6BhJX`šKo"ɋ&DDQd.hQGΊRhP(*٬F46%Y ~wTTE!!,0t֚8`6BhJX`šKo"ɋ&DD+>r;|.*T*ȮP(T ø|Nc=6^%U ~wNNE'!,0t֚8`6BhJX`šKo"ɋ'D2y,*(.YnNoP(, l^_$K ~xHHE0!,0s=8`6BhJX`Ioȋ'D2[ڊLd).6٢P丬Ff76t]J HR }wH~HE7!,0rЭ87Ʋנ(d:h2`VF@f "b]nFC5L19}Nm;mDz@ Q |~vL}LF@!,0qpI˻]H " !i]4'疍pTG1).MӉ@0oIenB!k81ڌI7,  {}uI|IFF!,0rIkmZ\8 " !i\&畍PTG1).MӉ@0oIenB!k81ڌI7:,'{}uI~F|CC @ !,0rIlZ\8 " !i\&畍PTG1).MӉ@0oIenB!k81ڌI7:,'{}uI~IFFY @<!,0sIkZ\8 " !i\&畍PTG1).MӉ@0oIenB!k81ڌI7:,I~I FF}uY@ {<!,0sIic=Z\8 " !i\&畍PTG1).MӉ@0oIenB!k81ڌI7:t2!>I}I CF@C<9!,0vIec=Z\8 " !i\&畍PTG1).MӉ@0oIenB!k81ڜh58>Cz=IY {IFF C@!,094 5(dh>X[ܴ& x=D҆[G,.Xh8"(  `a>ׇ6f!?t}~E|~H~ HE!,0uc4k`6(JhJ X`&͋ĆF8*@,렪-&Щp8\ ’l^h؎xKK wWFF?CݎNN uVFF?<9! ,0tGحo'Z by—Kwܵ׺_&vEb2xBiUiѢp 縬Ff8>BݎjuV vsE {O?;Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/cors/jquery.postmessage-transport.js0000644000000000000000000000764012237177136030674 0ustar 00000000000000/* * jQuery postMessage Transport Plugin 1.1 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ /*jslint unparam: true, nomen: true */ /*global define, window, document */ (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); } else { // Browser globals: factory(window.jQuery); } }(function ($) { 'use strict'; var counter = 0, names = [ 'accepts', 'cache', 'contents', 'contentType', 'crossDomain', 'data', 'dataType', 'headers', 'ifModified', 'mimeType', 'password', 'processData', 'timeout', 'traditional', 'type', 'url', 'username' ], convert = function (p) { return p; }; $.ajaxSetup({ converters: { 'postmessage text': convert, 'postmessage json': convert, 'postmessage html': convert } }); $.ajaxTransport('postmessage', function (options) { if (options.postMessage && window.postMessage) { var iframe, loc = $('').prop('href', options.postMessage)[0], target = loc.protocol + '//' + loc.host, xhrUpload = options.xhr().upload; return { send: function (_, completeCallback) { var message = { id: 'postmessage-transport-' + (counter += 1) }, eventName = 'message.' + message.id; iframe = $( '' ).bind('load', function () { $.each(names, function (i, name) { message[name] = options[name]; }); message.dataType = message.dataType.replace('postmessage ', ''); $(window).bind(eventName, function (e) { e = e.originalEvent; var data = e.data, ev; if (e.origin === target && data.id === message.id) { if (data.type === 'progress') { ev = document.createEvent('Event'); ev.initEvent(data.type, false, true); $.extend(ev, data); xhrUpload.dispatchEvent(ev); } else { completeCallback( data.status, data.statusText, {postmessage: data.result}, data.headers ); iframe.remove(); $(window).unbind(eventName); } } }); iframe[0].contentWindow.postMessage( message, target ); }).appendTo(document.body); }, abort: function () { if (iframe) { iframe.remove(); } } }; } }); })); Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/cors/jquery.xdr-transport.js0000644000000000000000000000615312237177136027135 0ustar 00000000000000/* * jQuery XDomainRequest Transport Plugin 1.1.2 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT * * Based on Julian Aubourg's ajaxHooks xdr.js: * https://github.com/jaubourg/ajaxHooks/ */ /*jslint unparam: true */ /*global define, window, XDomainRequest */ (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); } else { // Browser globals: factory(window.jQuery); } }(function ($) { 'use strict'; if (window.XDomainRequest && !$.support.cors) { $.ajaxTransport(function (s) { if (s.crossDomain && s.async) { if (s.timeout) { s.xdrTimeout = s.timeout; delete s.timeout; } var xdr; return { send: function (headers, completeCallback) { function callback(status, statusText, responses, responseHeaders) { xdr.onload = xdr.onerror = xdr.ontimeout = $.noop; xdr = null; completeCallback(status, statusText, responses, responseHeaders); } xdr = new XDomainRequest(); // XDomainRequest only supports GET and POST: if (s.type === 'DELETE') { s.url = s.url + (/\?/.test(s.url) ? '&' : '?') + '_method=DELETE'; s.type = 'POST'; } else if (s.type === 'PUT') { s.url = s.url + (/\?/.test(s.url) ? '&' : '?') + '_method=PUT'; s.type = 'POST'; } xdr.open(s.type, s.url); xdr.onload = function () { callback( 200, 'OK', {text: xdr.responseText}, 'Content-Type: ' + xdr.contentType ); }; xdr.onerror = function () { callback(404, 'Not Found'); }; if (s.xdrTimeout) { xdr.ontimeout = function () { callback(0, 'timeout'); }; xdr.timeout = s.xdrTimeout; } xdr.send((s.hasContent && s.data) || null); }, abort: function () { if (xdr) { xdr.onerror = $.noop(); xdr.abort(); } } }; } }); } })); Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/jquery.fileupload-fp.js0000644000000000000000000002032112237177136026060 0ustar 00000000000000/* * jQuery File Upload File Processing Plugin 1.0 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ /*jslint nomen: true, unparam: true, regexp: true */ /*global define, window, document */ (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', 'load-image', 'canvas-to-blob', './jquery.fileupload' ], factory); } else { // Browser globals: factory( window.jQuery, window.loadImage ); } }(function ($, loadImage) { 'use strict'; // The File Upload IP version extends the basic fileupload widget // with file processing functionality: $.widget('blueimpFP.fileupload', $.blueimp.fileupload, { options: { // The list of file processing actions: process: [ /* { action: 'load', fileTypes: /^image\/(gif|jpeg|png)$/, maxFileSize: 20000000 // 20MB }, { action: 'resize', maxWidth: 1920, maxHeight: 1200, minWidth: 800, minHeight: 600 }, { action: 'save' } */ ], // The add callback is invoked as soon as files are added to the // fileupload widget (via file input selection, drag & drop or add // API call). See the basic file upload widget for more information: add: function (e, data) { $(this).fileupload('process', data).done(function () { data.submit(); }); } }, processActions: { // Loads the image given via data.files and data.index // as canvas element. // Accepts the options fileTypes (regular expression) // and maxFileSize (integer) to limit the files to load: load: function (data, options) { var that = this, file = data.files[data.index], dfd = $.Deferred(); if (window.HTMLCanvasElement && window.HTMLCanvasElement.prototype.toBlob && ($.type(options.maxFileSize) !== 'number' || file.size < options.maxFileSize) && (!options.fileTypes || options.fileTypes.test(file.type))) { loadImage( file, function (canvas) { data.canvas = canvas; dfd.resolveWith(that, [data]); }, {canvas: true} ); } else { dfd.rejectWith(that, [data]); } return dfd.promise(); }, // Resizes the image given as data.canvas and updates // data.canvas with the resized image. // Accepts the options maxWidth, maxHeight, minWidth and // minHeight to scale the given image: resize: function (data, options) { if (data.canvas) { var canvas = loadImage.scale(data.canvas, options); if (canvas.width !== data.canvas.width || canvas.height !== data.canvas.height) { data.canvas = canvas; data.processed = true; } } return data; }, // Saves the processed image given as data.canvas // inplace at data.index of data.files: save: function (data, options) { // Do nothing if no processing has happened: if (!data.canvas || !data.processed) { return data; } var that = this, file = data.files[data.index], name = file.name, dfd = $.Deferred(), callback = function (blob) { if (!blob.name) { if (file.type === blob.type) { blob.name = file.name; } else if (file.name) { blob.name = file.name.replace( /\..+$/, '.' + blob.type.substr(6) ); } } // Store the created blob at the position // of the original file in the files list: data.files[data.index] = blob; dfd.resolveWith(that, [data]); }; // Use canvas.mozGetAsFile directly, to retain the filename, as // Gecko doesn't support the filename option for FormData.append: if (data.canvas.mozGetAsFile) { callback(data.canvas.mozGetAsFile( (/^image\/(jpeg|png)$/.test(file.type) && name) || ((name && name.replace(/\..+$/, '')) || 'blob') + '.png', file.type )); } else { data.canvas.toBlob(callback, file.type); } return dfd.promise(); } }, // Resizes the file at the given index and stores the created blob at // the original position of the files list, returns a Promise object: _processFile: function (files, index, options) { var that = this, dfd = $.Deferred().resolveWith(that, [{ files: files, index: index }]), chain = dfd.promise(); that._processing += 1; $.each(options.process, function (i, settings) { chain = chain.pipe(function (data) { return that.processActions[settings.action] .call(this, data, settings); }); }); chain.always(function () { that._processing -= 1; if (that._processing === 0) { that.element .removeClass('fileupload-processing'); } }); if (that._processing === 1) { that.element.addClass('fileupload-processing'); } return chain; }, // Processes the files given as files property of the data parameter, // returns a Promise object that allows to bind a done handler, which // will be invoked after processing all files (inplace) is done: process: function (data) { var that = this, options = $.extend({}, this.options, data); if (options.process && options.process.length && this._isXHRUpload(options)) { $.each(data.files, function (index, file) { that._processingQueue = that._processingQueue.pipe( function () { var dfd = $.Deferred(); that._processFile(data.files, index, options) .always(function () { dfd.resolveWith(that); }); return dfd.promise(); } ); }); } return this._processingQueue; }, _create: function () { $.blueimp.fileupload.prototype._create.call(this); this._processing = 0; this._processingQueue = $.Deferred().resolveWith(this) .promise(); } }); })); Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/jquery.fileupload-ui.js0000644000000000000000000006756412237177136026114 0ustar 00000000000000/* * jQuery File Upload User Interface Plugin 6.9.1 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ /*jslint nomen: true, unparam: true, regexp: true */ /*global define, window, document, URL, webkitURL, FileReader */ (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', 'tmpl', 'load-image', './jquery.fileupload-fp' ], factory); } else { // Browser globals: factory( window.jQuery, window.tmpl, window.loadImage ); } }(function ($, tmpl, loadImage) { 'use strict'; // The UI version extends the FP (file processing) version or the basic // file upload widget and adds complete user interface interaction: var parentWidget = ($.blueimpFP || $.blueimp).fileupload; $.widget('blueimpUI.fileupload', parentWidget, { options: { // By default, files added to the widget are uploaded as soon // as the user clicks on the start buttons. To enable automatic // uploads, set the following option to true: autoUpload: false, // The following option limits the number of files that are // allowed to be uploaded using this widget: maxNumberOfFiles: undefined, // The maximum allowed file size: maxFileSize: undefined, // The minimum allowed file size: minFileSize: undefined, // The regular expression for allowed file types, matches // against either file type or file name: acceptFileTypes: /.+$/i, // The regular expression to define for which files a preview // image is shown, matched against the file type: previewSourceFileTypes: /^image\/(gif|jpeg|png)$/, // The maximum file size of images that are to be displayed as preview: previewSourceMaxFileSize: 5000000, // 5MB // The maximum width of the preview images: previewMaxWidth: 80, // The maximum height of the preview images: previewMaxHeight: 80, // By default, preview images are displayed as canvas elements // if supported by the browser. Set the following option to false // to always display preview images as img elements: previewAsCanvas: true, // The ID of the upload template: uploadTemplateId: 'template-upload', // The ID of the download template: downloadTemplateId: 'template-download', // The container for the list of files. If undefined, it is set to // an element with class "files" inside of the widget element: filesContainer: undefined, // By default, files are appended to the files container. // Set the following option to true, to prepend files instead: prependFiles: false, // The expected data type of the upload response, sets the dataType // option of the $.ajax upload requests: dataType: 'json', // The add callback is invoked as soon as files are added to the fileupload // widget (via file input selection, drag & drop or add API call). // See the basic file upload widget for more information: add: function (e, data) { var that = $(this).data('fileupload'), options = that.options, files = data.files; $(this).fileupload('process', data).done(function () { that._adjustMaxNumberOfFiles(-files.length); data.isAdjusted = true; data.files.valid = data.isValidated = that._validate(files); data.context = that._renderUpload(files).data('data', data); options.filesContainer[ options.prependFiles ? 'prepend' : 'append' ](data.context); that._renderPreviews(files, data.context); that._forceReflow(data.context); that._transition(data.context).done( function () { if ((that._trigger('added', e, data) !== false) && (options.autoUpload || data.autoUpload) && data.autoUpload !== false && data.isValidated) { data.submit(); } } ); }); }, // Callback for the start of each file upload request: send: function (e, data) { var that = $(this).data('fileupload'); if (!data.isValidated) { if (!data.isAdjusted) { that._adjustMaxNumberOfFiles(-data.files.length); } if (!that._validate(data.files)) { return false; } } if (data.context && data.dataType && data.dataType.substr(0, 6) === 'iframe') { // Iframe Transport does not support progress events. // In lack of an indeterminate progress bar, we set // the progress to 100%, showing the full animated bar: data.context .find('.progress').addClass( !$.support.transition && 'progress-animated' ) .attr('aria-valuenow', 100) .find('.bar').css( 'width', '100%' ); } return that._trigger('sent', e, data); }, // Callback for successful uploads: done: function (e, data) { var that = $(this).data('fileupload'), template; if (data.context) { data.context.each(function (index) { var file = ($.isArray(data.result) && data.result[index]) || {error: 'emptyResult'}; if (file.error) { that._adjustMaxNumberOfFiles(1); } that._transition($(this)).done( function () { var node = $(this); template = that._renderDownload([file]) .css('height', node.height()) .replaceAll(node); that._forceReflow(template); that._transition(template).done( function () { data.context = $(this); that._trigger('completed', e, data); } ); } ); }); } else { template = that._renderDownload(data.result) .appendTo(that.options.filesContainer); that._forceReflow(template); that._transition(template).done( function () { data.context = $(this); that._trigger('completed', e, data); } ); } }, // Callback for failed (abort or error) uploads: fail: function (e, data) { var that = $(this).data('fileupload'), template; that._adjustMaxNumberOfFiles(data.files.length); if (data.context) { data.context.each(function (index) { if (data.errorThrown !== 'abort') { var file = data.files[index]; file.error = file.error || data.errorThrown || true; that._transition($(this)).done( function () { var node = $(this); template = that._renderDownload([file]) .replaceAll(node); that._forceReflow(template); that._transition(template).done( function () { data.context = $(this); that._trigger('failed', e, data); } ); } ); } else { that._transition($(this)).done( function () { $(this).remove(); that._trigger('failed', e, data); } ); } }); } else if (data.errorThrown !== 'abort') { that._adjustMaxNumberOfFiles(-data.files.length); data.context = that._renderUpload(data.files) .appendTo(that.options.filesContainer) .data('data', data); that._forceReflow(data.context); that._transition(data.context).done( function () { data.context = $(this); that._trigger('failed', e, data); } ); } else { that._trigger('failed', e, data); } }, // Callback for upload progress events: progress: function (e, data) { if (data.context) { var progress = parseInt(data.loaded / data.total * 100, 10); data.context.find('.progress') .attr('aria-valuenow', progress) .find('.bar').css( 'width', progress + '%' ); } }, // Callback for global upload progress events: progressall: function (e, data) { var $this = $(this), progress = parseInt(data.loaded / data.total * 100, 10), globalProgressNode = $this.find('.fileupload-progress'), extendedProgressNode = globalProgressNode .find('.progress-extended'); if (extendedProgressNode.length) { extendedProgressNode.html( $this.data('fileupload')._renderExtendedProgress(data) ); } globalProgressNode .find('.progress') .attr('aria-valuenow', progress) .find('.bar').css( 'width', progress + '%' ); }, // Callback for uploads start, equivalent to the global ajaxStart event: start: function (e) { var that = $(this).data('fileupload'); that._transition($(this).find('.fileupload-progress')).done( function () { that._trigger('started', e); } ); }, // Callback for uploads stop, equivalent to the global ajaxStop event: stop: function (e) { var that = $(this).data('fileupload'); that._transition($(this).find('.fileupload-progress')).done( function () { $(this).find('.progress') .attr('aria-valuenow', '0') .find('.bar').css('width', '0%'); $(this).find('.progress-extended').html(' '); that._trigger('stopped', e); } ); }, // Callback for file deletion: destroy: function (e, data) { var that = $(this).data('fileupload'); if (data.url) { $.ajax(data); that._adjustMaxNumberOfFiles(1); } that._transition(data.context).done( function () { $(this).remove(); that._trigger('destroyed', e, data); } ); } }, // Link handler, that allows to download files // by drag & drop of the links to the desktop: _enableDragToDesktop: function () { var link = $(this), url = link.prop('href'), name = link.prop('download'), type = 'application/octet-stream'; link.bind('dragstart', function (e) { try { e.originalEvent.dataTransfer.setData( 'DownloadURL', [type, name, url].join(':') ); } catch (err) {} }); }, _adjustMaxNumberOfFiles: function (operand) { if (typeof this.options.maxNumberOfFiles === 'number') { this.options.maxNumberOfFiles += operand; if (this.options.maxNumberOfFiles < 1) { this._disableFileInputButton(); } else { this._enableFileInputButton(); } } }, _formatFileSize: function (bytes) { if (typeof bytes !== 'number') { return ''; } if (bytes >= 1000000000) { return (bytes / 1000000000).toFixed(2) + ' GB'; } if (bytes >= 1000000) { return (bytes / 1000000).toFixed(2) + ' MB'; } return (bytes / 1000).toFixed(2) + ' KB'; }, _formatBitrate: function (bits) { if (typeof bits !== 'number') { return ''; } if (bits >= 1000000000) { return (bits / 1000000000).toFixed(2) + ' Gbit/s'; } if (bits >= 1000000) { return (bits / 1000000).toFixed(2) + ' Mbit/s'; } if (bits >= 1000) { return (bits / 1000).toFixed(2) + ' kbit/s'; } return bits + ' bit/s'; }, _formatTime: function (seconds) { var date = new Date(seconds * 1000), days = parseInt(seconds / 86400, 10); days = days ? days + 'd ' : ''; return days + ('0' + date.getUTCHours()).slice(-2) + ':' + ('0' + date.getUTCMinutes()).slice(-2) + ':' + ('0' + date.getUTCSeconds()).slice(-2); }, _formatPercentage: function (floatValue) { return (floatValue * 100).toFixed(2) + ' %'; }, _renderExtendedProgress: function (data) { return this._formatBitrate(data.bitrate) + ' | ' + this._formatTime( (data.total - data.loaded) * 8 / data.bitrate ) + ' | ' + this._formatPercentage( data.loaded / data.total ) + ' | ' + this._formatFileSize(data.loaded) + ' / ' + this._formatFileSize(data.total); }, _hasError: function (file) { if (file.error) { return file.error; } // The number of added files is subtracted from // maxNumberOfFiles before validation, so we check if // maxNumberOfFiles is below 0 (instead of below 1): if (this.options.maxNumberOfFiles < 0) { return 'maxNumberOfFiles'; } // Files are accepted if either the file type or the file name // matches against the acceptFileTypes regular expression, as // only browsers with support for the File API report the type: if (!(this.options.acceptFileTypes.test(file.type) || this.options.acceptFileTypes.test(file.name))) { return 'acceptFileTypes'; } if (this.options.maxFileSize && file.size > this.options.maxFileSize) { return 'maxFileSize'; } if (typeof file.size === 'number' && file.size < this.options.minFileSize) { return 'minFileSize'; } return null; }, _validate: function (files) { var that = this, valid = !!files.length; $.each(files, function (index, file) { file.error = that._hasError(file); if (file.error) { valid = false; } }); return valid; }, _renderTemplate: function (func, files) { if (!func) { return $(); } var result = func({ files: files, formatFileSize: this._formatFileSize, options: this.options }); if (result instanceof $) { return result; } return $(this.options.templatesContainer).html(result).children(); }, _renderPreview: function (file, node) { var that = this, options = this.options, dfd = $.Deferred(); return ((loadImage && loadImage( file, function (img) { node.append(img); that._forceReflow(node); that._transition(node).done(function () { dfd.resolveWith(node); }); if (!$.contains(document.body, node[0])) { // If the element is not part of the DOM, // transition events are not triggered, // so we have to resolve manually: dfd.resolveWith(node); } }, { maxWidth: options.previewMaxWidth, maxHeight: options.previewMaxHeight, canvas: options.previewAsCanvas } )) || dfd.resolveWith(node)) && dfd; }, _renderPreviews: function (files, nodes) { var that = this, options = this.options; nodes.find('.preview span').each(function (index, element) { var file = files[index]; if (options.previewSourceFileTypes.test(file.type) && ($.type(options.previewSourceMaxFileSize) !== 'number' || file.size < options.previewSourceMaxFileSize)) { that._processingQueue = that._processingQueue.pipe(function () { var dfd = $.Deferred(); that._renderPreview(file, $(element)).done( function () { dfd.resolveWith(that); } ); return dfd.promise(); }); } }); return this._processingQueue; }, _renderUpload: function (files) { return this._renderTemplate( this.options.uploadTemplate, files ); }, _renderDownload: function (files) { return this._renderTemplate( this.options.downloadTemplate, files ).find('a[download]').each(this._enableDragToDesktop).end(); }, _startHandler: function (e) { e.preventDefault(); var button = $(this), template = button.closest('.template-upload'), data = template.data('data'); if (data && data.submit && !data.jqXHR && data.submit()) { button.prop('disabled', true); } }, _cancelHandler: function (e) { e.preventDefault(); var template = $(this).closest('.template-upload'), data = template.data('data') || {}; if (!data.jqXHR) { data.errorThrown = 'abort'; e.data.fileupload._trigger('fail', e, data); } else { data.jqXHR.abort(); } }, _deleteHandler: function (e) { e.preventDefault(); var button = $(this); e.data.fileupload._trigger('destroy', e, { context: button.closest('.template-download'), url: button.attr('data-url'), type: button.attr('data-type') || 'DELETE', dataType: e.data.fileupload.options.dataType }); }, _forceReflow: function (node) { return $.support.transition && node.length && node[0].offsetWidth; }, _transition: function (node) { var dfd = $.Deferred(); if ($.support.transition && node.hasClass('fade')) { node.bind( $.support.transition.end, function (e) { // Make sure we don't respond to other transitions events // in the container element, e.g. from button elements: if (e.target === node[0]) { node.unbind($.support.transition.end); dfd.resolveWith(node); } } ).toggleClass('in'); } else { node.toggleClass('in'); dfd.resolveWith(node); } return dfd; }, _initButtonBarEventHandlers: function () { var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'), filesList = this.options.filesContainer, ns = this.options.namespace; fileUploadButtonBar.find('.start') .bind('click.' + ns, function (e) { e.preventDefault(); filesList.find('.start button').click(); }); fileUploadButtonBar.find('.cancel') .bind('click.' + ns, function (e) { e.preventDefault(); filesList.find('.cancel button').click(); }); fileUploadButtonBar.find('.delete') .bind('click.' + ns, function (e) { e.preventDefault(); filesList.find('.delete input:checked') .siblings('button').click(); fileUploadButtonBar.find('.toggle') .prop('checked', false); }); fileUploadButtonBar.find('.toggle') .bind('change.' + ns, function (e) { filesList.find('.delete input').prop( 'checked', $(this).is(':checked') ); }); }, _destroyButtonBarEventHandlers: function () { this.element.find('.fileupload-buttonbar button') .unbind('click.' + this.options.namespace); this.element.find('.fileupload-buttonbar .toggle') .unbind('change.' + this.options.namespace); }, _initEventHandlers: function () { parentWidget.prototype._initEventHandlers.call(this); var eventData = {fileupload: this}; this.options.filesContainer .delegate( '.start button', 'click.' + this.options.namespace, eventData, this._startHandler ) .delegate( '.cancel button', 'click.' + this.options.namespace, eventData, this._cancelHandler ) .delegate( '.delete button', 'click.' + this.options.namespace, eventData, this._deleteHandler ); this._initButtonBarEventHandlers(); }, _destroyEventHandlers: function () { var options = this.options; this._destroyButtonBarEventHandlers(); options.filesContainer .undelegate('.start button', 'click.' + options.namespace) .undelegate('.cancel button', 'click.' + options.namespace) .undelegate('.delete button', 'click.' + options.namespace); parentWidget.prototype._destroyEventHandlers.call(this); }, _enableFileInputButton: function () { this.element.find('.fileinput-button input') .prop('disabled', false) .parent().removeClass('disabled'); }, _disableFileInputButton: function () { this.element.find('.fileinput-button input') .prop('disabled', true) .parent().addClass('disabled'); }, _initTemplates: function () { var options = this.options; options.templatesContainer = document.createElement( options.filesContainer.prop('nodeName') ); if (tmpl) { if (options.uploadTemplateId) { options.uploadTemplate = tmpl(options.uploadTemplateId); } if (options.downloadTemplateId) { options.downloadTemplate = tmpl(options.downloadTemplateId); } } }, _initFilesContainer: function () { var options = this.options; if (options.filesContainer === undefined) { options.filesContainer = this.element.find('.files'); } else if (!(options.filesContainer instanceof $)) { options.filesContainer = $(options.filesContainer); } }, _initSpecialOptions: function () { parentWidget.prototype._initSpecialOptions.call(this); this._initFilesContainer(); this._initTemplates(); }, _create: function () { parentWidget.prototype._create.call(this); this._refreshOptionsList.push( 'filesContainer', 'uploadTemplateId', 'downloadTemplateId' ); if (!$.blueimpFP) { this._processingQueue = $.Deferred().resolveWith(this).promise(); this.process = function () { return this._processingQueue; }; } }, enable: function () { parentWidget.prototype.enable.call(this); this.element.find('input, button').prop('disabled', false); this._enableFileInputButton(); }, disable: function () { this.element.find('input, button').prop('disabled', true); this._disableFileInputButton(); parentWidget.prototype.disable.call(this); } }); })); Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/jquery.fileupload.js0000644000000000000000000012375112237177136025470 0ustar 00000000000000/* * jQuery File Upload Plugin 5.12 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ /*jslint nomen: true, unparam: true, regexp: true */ /*global define, window, document, Blob, FormData, location */ (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define([ 'jquery', 'jquery.ui.widget' ], factory); } else { // Browser globals: factory(window.jQuery); } }(function ($) { 'use strict'; // The FileReader API is not actually used, but works as feature detection, // as e.g. Safari supports XHR file uploads via the FormData API, // but not non-multipart XHR file uploads: $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader); $.support.xhrFormDataFileUpload = !!window.FormData; // The fileupload widget listens for change events on file input fields defined // via fileInput setting and paste or drop events of the given dropZone. // In addition to the default jQuery Widget methods, the fileupload widget // exposes the "add" and "send" methods, to add or directly send files using // the fileupload API. // By default, files added via file input selection, paste, drag & drop or // "add" method are uploaded immediately, but it is possible to override // the "add" callback option to queue file uploads. $.widget('blueimp.fileupload', { options: { // The namespace used for event handler binding on the dropZone and // fileInput collections. // If not set, the name of the widget ("fileupload") is used. namespace: undefined, // The drop target collection, by the default the complete document. // Set to null or an empty collection to disable drag & drop support: dropZone: $(document), // The file input field collection, that is listened for change events. // If undefined, it is set to the file input fields inside // of the widget element on plugin initialization. // Set to null or an empty collection to disable the change listener. fileInput: undefined, // By default, the file input field is replaced with a clone after // each input field change event. This is required for iframe transport // queues and allows change events to be fired for the same file // selection, but can be disabled by setting the following option to false: replaceFileInput: true, // The parameter name for the file form data (the request argument name). // If undefined or empty, the name property of the file input field is // used, or "files[]" if the file input name property is also empty, // can be a string or an array of strings: paramName: undefined, // By default, each file of a selection is uploaded using an individual // request for XHR type uploads. Set to false to upload file // selections in one request each: singleFileUploads: true, // To limit the number of files uploaded with one XHR request, // set the following option to an integer greater than 0: limitMultiFileUploads: undefined, // Set the following option to true to issue all file upload requests // in a sequential order: sequentialUploads: false, // To limit the number of concurrent uploads, // set the following option to an integer greater than 0: limitConcurrentUploads: undefined, // Set the following option to true to force iframe transport uploads: forceIframeTransport: false, // Set the following option to the location of a redirect url on the // origin server, for cross-domain iframe transport uploads: redirect: undefined, // The parameter name for the redirect url, sent as part of the form // data and set to 'redirect' if this option is empty: redirectParamName: undefined, // Set the following option to the location of a postMessage window, // to enable postMessage transport uploads: postMessage: undefined, // By default, XHR file uploads are sent as multipart/form-data. // The iframe transport is always using multipart/form-data. // Set to false to enable non-multipart XHR uploads: multipart: true, // To upload large files in smaller chunks, set the following option // to a preferred maximum chunk size. If set to 0, null or undefined, // or the browser does not support the required Blob API, files will // be uploaded as a whole. maxChunkSize: undefined, // When a non-multipart upload or a chunked multipart upload has been // aborted, this option can be used to resume the upload by setting // it to the size of the already uploaded bytes. This option is most // useful when modifying the options object inside of the "add" or // "send" callbacks, as the options are cloned for each file upload. uploadedBytes: undefined, // By default, failed (abort or error) file uploads are removed from the // global progress calculation. Set the following option to false to // prevent recalculating the global progress data: recalculateProgress: true, // Interval in milliseconds to calculate and trigger progress events: progressInterval: 100, // Interval in milliseconds to calculate progress bitrate: bitrateInterval: 500, // Additional form data to be sent along with the file uploads can be set // using this option, which accepts an array of objects with name and // value properties, a function returning such an array, a FormData // object (for XHR file uploads), or a simple object. // The form of the first fileInput is given as parameter to the function: formData: function (form) { return form.serializeArray(); }, // The add callback is invoked as soon as files are added to the fileupload // widget (via file input selection, drag & drop, paste or add API call). // If the singleFileUploads option is enabled, this callback will be // called once for each file in the selection for XHR file uplaods, else // once for each file selection. // The upload starts when the submit method is invoked on the data parameter. // The data object contains a files property holding the added files // and allows to override plugin options as well as define ajax settings. // Listeners for this callback can also be bound the following way: // .bind('fileuploadadd', func); // data.submit() returns a Promise object and allows to attach additional // handlers using jQuery's Deferred callbacks: // data.submit().done(func).fail(func).always(func); add: function (e, data) { data.submit(); }, // Other callbacks: // Callback for the submit event of each file upload: // submit: function (e, data) {}, // .bind('fileuploadsubmit', func); // Callback for the start of each file upload request: // send: function (e, data) {}, // .bind('fileuploadsend', func); // Callback for successful uploads: // done: function (e, data) {}, // .bind('fileuploaddone', func); // Callback for failed (abort or error) uploads: // fail: function (e, data) {}, // .bind('fileuploadfail', func); // Callback for completed (success, abort or error) requests: // always: function (e, data) {}, // .bind('fileuploadalways', func); // Callback for upload progress events: // progress: function (e, data) {}, // .bind('fileuploadprogress', func); // Callback for global upload progress events: // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); // Callback for uploads start, equivalent to the global ajaxStart event: // start: function (e) {}, // .bind('fileuploadstart', func); // Callback for uploads stop, equivalent to the global ajaxStop event: // stop: function (e) {}, // .bind('fileuploadstop', func); // Callback for change events of the fileInput collection: // change: function (e, data) {}, // .bind('fileuploadchange', func); // Callback for paste events to the dropZone collection: // paste: function (e, data) {}, // .bind('fileuploadpaste', func); // Callback for drop events of the dropZone collection: // drop: function (e, data) {}, // .bind('fileuploaddrop', func); // Callback for dragover events of the dropZone collection: // dragover: function (e) {}, // .bind('fileuploaddragover', func); // The plugin options are used as settings object for the ajax calls. // The following are jQuery ajax settings required for the file uploads: processData: false, contentType: false, cache: false }, // A list of options that require a refresh after assigning a new value: _refreshOptionsList: [ 'namespace', 'dropZone', 'fileInput', 'multipart', 'forceIframeTransport' ], _BitrateTimer: function () { this.timestamp = +(new Date()); this.loaded = 0; this.bitrate = 0; this.getBitrate = function (now, loaded, interval) { var timeDiff = now - this.timestamp; if (!this.bitrate || !interval || timeDiff > interval) { this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; this.loaded = loaded; this.timestamp = now; } return this.bitrate; }; }, _isXHRUpload: function (options) { return !options.forceIframeTransport && ((!options.multipart && $.support.xhrFileUpload) || $.support.xhrFormDataFileUpload); }, _getFormData: function (options) { var formData; if (typeof options.formData === 'function') { return options.formData(options.form); } if ($.isArray(options.formData)) { return options.formData; } if (options.formData) { formData = []; $.each(options.formData, function (name, value) { formData.push({name: name, value: value}); }); return formData; } return []; }, _getTotal: function (files) { var total = 0; $.each(files, function (index, file) { total += file.size || 1; }); return total; }, _onProgress: function (e, data) { if (e.lengthComputable) { var now = +(new Date()), total, loaded; if (data._time && data.progressInterval && (now - data._time < data.progressInterval) && e.loaded !== e.total) { return; } data._time = now; total = data.total || this._getTotal(data.files); loaded = parseInt( e.loaded / e.total * (data.chunkSize || total), 10 ) + (data.uploadedBytes || 0); this._loaded += loaded - (data.loaded || data.uploadedBytes || 0); data.lengthComputable = true; data.loaded = loaded; data.total = total; data.bitrate = data._bitrateTimer.getBitrate( now, loaded, data.bitrateInterval ); // Trigger a custom progress event with a total data property set // to the file size(s) of the current upload and a loaded data // property calculated accordingly: this._trigger('progress', e, data); // Trigger a global progress event for all current file uploads, // including ajax calls queued for sequential file uploads: this._trigger('progressall', e, { lengthComputable: true, loaded: this._loaded, total: this._total, bitrate: this._bitrateTimer.getBitrate( now, this._loaded, data.bitrateInterval ) }); } }, _initProgressListener: function (options) { var that = this, xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); // Accesss to the native XHR object is required to add event listeners // for the upload progress event: if (xhr.upload) { $(xhr.upload).bind('progress', function (e) { var oe = e.originalEvent; // Make sure the progress event properties get copied over: e.lengthComputable = oe.lengthComputable; e.loaded = oe.loaded; e.total = oe.total; that._onProgress(e, options); }); options.xhr = function () { return xhr; }; } }, _initXHRData: function (options) { var formData, file = options.files[0], // Ignore non-multipart setting if not supported: multipart = options.multipart || !$.support.xhrFileUpload, paramName = options.paramName[0]; if (!multipart || options.blob) { // For non-multipart uploads and chunked uploads, // file meta data is not part of the request body, // so we transmit this data as part of the HTTP headers. // For cross domain requests, these headers must be allowed // via Access-Control-Allow-Headers or removed using // the beforeSend callback: options.headers = $.extend(options.headers, { 'X-File-Name': file.name, 'X-File-Type': file.type, 'X-File-Size': file.size }); if (!options.blob) { // Non-chunked non-multipart upload: options.contentType = file.type; options.data = file; } else if (!multipart) { // Chunked non-multipart upload: options.contentType = 'application/octet-stream'; options.data = options.blob; } } if (multipart && $.support.xhrFormDataFileUpload) { if (options.postMessage) { // window.postMessage does not allow sending FormData // objects, so we just add the File/Blob objects to // the formData array and let the postMessage window // create the FormData object out of this array: formData = this._getFormData(options); if (options.blob) { formData.push({ name: paramName, value: options.blob }); } else { $.each(options.files, function (index, file) { formData.push({ name: options.paramName[index] || paramName, value: file }); }); } } else { if (options.formData instanceof FormData) { formData = options.formData; } else { formData = new FormData(); $.each(this._getFormData(options), function (index, field) { formData.append(field.name, field.value); }); } if (options.blob) { formData.append(paramName, options.blob, file.name); } else { $.each(options.files, function (index, file) { // File objects are also Blob instances. // This check allows the tests to run with // dummy objects: if (file instanceof Blob) { formData.append( options.paramName[index] || paramName, file, file.name ); } }); } } options.data = formData; } // Blob reference is not needed anymore, free memory: options.blob = null; }, _initIframeSettings: function (options) { // Setting the dataType to iframe enables the iframe transport: options.dataType = 'iframe ' + (options.dataType || ''); // The iframe transport accepts a serialized array as form data: options.formData = this._getFormData(options); // Add redirect url to form data on cross-domain uploads: if (options.redirect && $('').prop('href', options.url) .prop('host') !== location.host) { options.formData.push({ name: options.redirectParamName || 'redirect', value: options.redirect }); } }, _initDataSettings: function (options) { if (this._isXHRUpload(options)) { if (!this._chunkedUpload(options, true)) { if (!options.data) { this._initXHRData(options); } this._initProgressListener(options); } if (options.postMessage) { // Setting the dataType to postmessage enables the // postMessage transport: options.dataType = 'postmessage ' + (options.dataType || ''); } } else { this._initIframeSettings(options, 'iframe'); } }, _getParamName: function (options) { var fileInput = $(options.fileInput), paramName = options.paramName; if (!paramName) { paramName = []; fileInput.each(function () { var input = $(this), name = input.prop('name') || 'files[]', i = (input.prop('files') || [1]).length; while (i) { paramName.push(name); i -= 1; } }); if (!paramName.length) { paramName = [fileInput.prop('name') || 'files[]']; } } else if (!$.isArray(paramName)) { paramName = [paramName]; } return paramName; }, _initFormSettings: function (options) { // Retrieve missing options from the input field and the // associated form, if available: if (!options.form || !options.form.length) { options.form = $(options.fileInput.prop('form')); } options.paramName = this._getParamName(options); if (!options.url) { options.url = options.form.prop('action') || location.href; } // The HTTP request method must be "POST" or "PUT": options.type = (options.type || options.form.prop('method') || '') .toUpperCase(); if (options.type !== 'POST' && options.type !== 'PUT') { options.type = 'POST'; } }, _getAJAXSettings: function (data) { var options = $.extend({}, this.options, data); this._initFormSettings(options); this._initDataSettings(options); return options; }, // Maps jqXHR callbacks to the equivalent // methods of the given Promise object: _enhancePromise: function (promise) { promise.success = promise.done; promise.error = promise.fail; promise.complete = promise.always; return promise; }, // Creates and returns a Promise object enhanced with // the jqXHR methods abort, success, error and complete: _getXHRPromise: function (resolveOrReject, context, args) { var dfd = $.Deferred(), promise = dfd.promise(); context = context || this.options.context || promise; if (resolveOrReject === true) { dfd.resolveWith(context, args); } else if (resolveOrReject === false) { dfd.rejectWith(context, args); } promise.abort = dfd.promise; return this._enhancePromise(promise); }, // Uploads a file in multiple, sequential requests // by splitting the file up in multiple blob chunks. // If the second parameter is true, only tests if the file // should be uploaded in chunks, but does not invoke any // upload requests: _chunkedUpload: function (options, testOnly) { var that = this, file = options.files[0], fs = file.size, ub = options.uploadedBytes = options.uploadedBytes || 0, mcs = options.maxChunkSize || fs, // Use the Blob methods with the slice implementation // according to the W3C Blob API specification: slice = file.webkitSlice || file.mozSlice || file.slice, upload, n, jqXHR, pipe; if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || options.data) { return false; } if (testOnly) { return true; } if (ub >= fs) { file.error = 'uploadedBytes'; return this._getXHRPromise( false, options.context, [null, 'error', file.error] ); } // n is the number of blobs to upload, // calculated via filesize, uploaded bytes and max chunk size: n = Math.ceil((fs - ub) / mcs); // The chunk upload method accepting the chunk number as parameter: upload = function (i) { if (!i) { return that._getXHRPromise(true, options.context); } // Upload the blobs in sequential order: return upload(i -= 1).pipe(function () { // Clone the options object for each chunk upload: var o = $.extend({}, options); o.blob = slice.call( file, ub + i * mcs, ub + (i + 1) * mcs ); // Store the current chunk size, as the blob itself // will be dereferenced after data processing: o.chunkSize = o.blob.size; // Process the upload data (the blob and potential form data): that._initXHRData(o); // Add progress listeners for this chunk upload: that._initProgressListener(o); jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context)) .done(function () { // Create a progress event if upload is done and // no progress event has been invoked for this chunk: if (!o.loaded) { that._onProgress($.Event('progress', { lengthComputable: true, loaded: o.chunkSize, total: o.chunkSize }), o); } options.uploadedBytes = o.uploadedBytes += o.chunkSize; }); return jqXHR; }); }; // Return the piped Promise object, enhanced with an abort method, // which is delegated to the jqXHR object of the current upload, // and jqXHR callbacks mapped to the equivalent Promise methods: pipe = upload(n); pipe.abort = function () { return jqXHR.abort(); }; return this._enhancePromise(pipe); }, _beforeSend: function (e, data) { if (this._active === 0) { // the start callback is triggered when an upload starts // and no other uploads are currently running, // equivalent to the global ajaxStart event: this._trigger('start'); // Set timer for global bitrate progress calculation: this._bitrateTimer = new this._BitrateTimer(); } this._active += 1; // Initialize the global progress values: this._loaded += data.uploadedBytes || 0; this._total += this._getTotal(data.files); }, _onDone: function (result, textStatus, jqXHR, options) { if (!this._isXHRUpload(options)) { // Create a progress event for each iframe load: this._onProgress($.Event('progress', { lengthComputable: true, loaded: 1, total: 1 }), options); } options.result = result; options.textStatus = textStatus; options.jqXHR = jqXHR; this._trigger('done', null, options); }, _onFail: function (jqXHR, textStatus, errorThrown, options) { options.jqXHR = jqXHR; options.textStatus = textStatus; options.errorThrown = errorThrown; this._trigger('fail', null, options); if (options.recalculateProgress) { // Remove the failed (error or abort) file upload from // the global progress calculation: this._loaded -= options.loaded || options.uploadedBytes || 0; this._total -= options.total || this._getTotal(options.files); } }, _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { this._active -= 1; options.textStatus = textStatus; if (jqXHRorError && jqXHRorError.always) { options.jqXHR = jqXHRorError; options.result = jqXHRorResult; } else { options.jqXHR = jqXHRorResult; options.errorThrown = jqXHRorError; } this._trigger('always', null, options); if (this._active === 0) { // The stop callback is triggered when all uploads have // been completed, equivalent to the global ajaxStop event: this._trigger('stop'); // Reset the global progress values: this._loaded = this._total = 0; this._bitrateTimer = null; } }, _onSend: function (e, data) { var that = this, jqXHR, slot, pipe, options = that._getAJAXSettings(data), send = function (resolve, args) { that._sending += 1; // Set timer for bitrate progress calculation: options._bitrateTimer = new that._BitrateTimer(); jqXHR = jqXHR || ( (resolve !== false && that._trigger('send', e, options) !== false && (that._chunkedUpload(options) || $.ajax(options))) || that._getXHRPromise(false, options.context, args) ).done(function (result, textStatus, jqXHR) { that._onDone(result, textStatus, jqXHR, options); }).fail(function (jqXHR, textStatus, errorThrown) { that._onFail(jqXHR, textStatus, errorThrown, options); }).always(function (jqXHRorResult, textStatus, jqXHRorError) { that._sending -= 1; that._onAlways( jqXHRorResult, textStatus, jqXHRorError, options ); if (options.limitConcurrentUploads && options.limitConcurrentUploads > that._sending) { // Start the next queued upload, // that has not been aborted: var nextSlot = that._slots.shift(); while (nextSlot) { if (!nextSlot.isRejected()) { nextSlot.resolve(); break; } nextSlot = that._slots.shift(); } } }); return jqXHR; }; this._beforeSend(e, options); if (this.options.sequentialUploads || (this.options.limitConcurrentUploads && this.options.limitConcurrentUploads <= this._sending)) { if (this.options.limitConcurrentUploads > 1) { slot = $.Deferred(); this._slots.push(slot); pipe = slot.pipe(send); } else { pipe = (this._sequence = this._sequence.pipe(send, send)); } // Return the piped Promise object, enhanced with an abort method, // which is delegated to the jqXHR object of the current upload, // and jqXHR callbacks mapped to the equivalent Promise methods: pipe.abort = function () { var args = [undefined, 'abort', 'abort']; if (!jqXHR) { if (slot) { slot.rejectWith(args); } return send(false, args); } return jqXHR.abort(); }; return this._enhancePromise(pipe); } return send(); }, _onAdd: function (e, data) { var that = this, result = true, options = $.extend({}, this.options, data), limit = options.limitMultiFileUploads, paramName = this._getParamName(options), paramNameSet, paramNameSlice, fileSet, i; if (!(options.singleFileUploads || limit) || !this._isXHRUpload(options)) { fileSet = [data.files]; paramNameSet = [paramName]; } else if (!options.singleFileUploads && limit) { fileSet = []; paramNameSet = []; for (i = 0; i < data.files.length; i += limit) { fileSet.push(data.files.slice(i, i + limit)); paramNameSlice = paramName.slice(i, i + limit); if (!paramNameSlice.length) { paramNameSlice = paramName; } paramNameSet.push(paramNameSlice); } } else { paramNameSet = paramName; } data.originalFiles = data.files; $.each(fileSet || data.files, function (index, element) { var newData = $.extend({}, data); newData.files = fileSet ? element : [element]; newData.paramName = paramNameSet[index]; newData.submit = function () { newData.jqXHR = this.jqXHR = (that._trigger('submit', e, this) !== false) && that._onSend(e, this); return this.jqXHR; }; return (result = that._trigger('add', e, newData)); }); return result; }, // File Normalization for Gecko 1.9.1 (Firefox 3.5) support: _normalizeFile: function (index, file) { if (file.name === undefined && file.size === undefined) { file.name = file.fileName; file.size = file.fileSize; } }, _replaceFileInput: function (input) { var inputClone = input.clone(true); $('
      ').append(inputClone)[0].reset(); // Detaching allows to insert the fileInput on another form // without loosing the file input value: input.after(inputClone).detach(); // Avoid memory leaks with the detached file input: $.cleanData(input.unbind('remove')); // Replace the original file input element in the fileInput // collection with the clone, which has been copied including // event handlers: this.options.fileInput = this.options.fileInput.map(function (i, el) { if (el === input[0]) { return inputClone[0]; } return el; }); // If the widget has been initialized on the file input itself, // override this.element with the file input clone: if (input[0] === this.element[0]) { this.element = inputClone; } }, _getFileInputFiles: function (fileInput) { fileInput = $(fileInput); var files = $.each($.makeArray(fileInput.prop('files')), this._normalizeFile), value; if (!files.length) { value = fileInput.prop('value'); if (!value) { return []; } // If the files property is not available, the browser does not // support the File API and we add a pseudo File object with // the input value as name with path information removed: files = [{name: value.replace(/^.*\\/, '')}]; } return files; }, _onChange: function (e) { var that = e.data.fileupload, data = { fileInput: $(e.target), form: $(e.target.form) }; data.files = that._getFileInputFiles(data.fileInput); if (that.options.replaceFileInput) { that._replaceFileInput(data.fileInput); } if (that._trigger('change', e, data) === false || that._onAdd(e, data) === false) { return false; } }, _onPaste: function (e) { var that = e.data.fileupload, cbd = e.originalEvent.clipboardData, items = (cbd && cbd.items) || [], data = {files: []}; $.each(items, function (index, item) { var file = item.getAsFile && item.getAsFile(); if (file) { data.files.push(file); } }); if (that._trigger('paste', e, data) === false || that._onAdd(e, data) === false) { return false; } }, _onDrop: function (e) { var that = e.data.fileupload, dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer, data = { files: $.each( $.makeArray(dataTransfer && dataTransfer.files), that._normalizeFile ) }; if (that._trigger('drop', e, data) === false || that._onAdd(e, data) === false) { return false; } e.preventDefault(); }, _onDragOver: function (e) { var that = e.data.fileupload, dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer; if (that._trigger('dragover', e) === false) { return false; } if (dataTransfer) { dataTransfer.dropEffect = 'copy'; } e.preventDefault(); }, _initEventHandlers: function () { var ns = this.options.namespace; if (this._isXHRUpload(this.options)) { this.options.dropZone .bind('dragover.' + ns, {fileupload: this}, this._onDragOver) .bind('drop.' + ns, {fileupload: this}, this._onDrop) .bind('paste.' + ns, {fileupload: this}, this._onPaste); } this.options.fileInput .bind('change.' + ns, {fileupload: this}, this._onChange); }, _destroyEventHandlers: function () { var ns = this.options.namespace; this.options.dropZone .unbind('dragover.' + ns, this._onDragOver) .unbind('drop.' + ns, this._onDrop) .unbind('paste.' + ns, this._onPaste); this.options.fileInput .unbind('change.' + ns, this._onChange); }, _setOption: function (key, value) { var refresh = $.inArray(key, this._refreshOptionsList) !== -1; if (refresh) { this._destroyEventHandlers(); } $.Widget.prototype._setOption.call(this, key, value); if (refresh) { this._initSpecialOptions(); this._initEventHandlers(); } }, _initSpecialOptions: function () { var options = this.options; if (options.fileInput === undefined) { options.fileInput = this.element.is('input:file') ? this.element : this.element.find('input:file'); } else if (!(options.fileInput instanceof $)) { options.fileInput = $(options.fileInput); } if (!(options.dropZone instanceof $)) { options.dropZone = $(options.dropZone); } }, _create: function () { var options = this.options; // Initialize options set via HTML5 data-attributes: $.extend(options, $(this.element[0].cloneNode(false)).data()); options.namespace = options.namespace || this.widgetName; this._initSpecialOptions(); this._slots = []; this._sequence = this._getXHRPromise(true); this._sending = this._active = this._loaded = this._total = 0; this._initEventHandlers(); }, destroy: function () { this._destroyEventHandlers(); $.Widget.prototype.destroy.call(this); }, enable: function () { $.Widget.prototype.enable.call(this); this._initEventHandlers(); }, disable: function () { this._destroyEventHandlers(); $.Widget.prototype.disable.call(this); }, // This method is exposed to the widget API and allows adding files // using the fileupload API. The data parameter accepts an object which // must have a files property and can contain additional options: // .fileupload('add', {files: filesList}); add: function (data) { if (!data || this.options.disabled) { return; } if (data.fileInput && !data.files) { data.files = this._getFileInputFiles(data.fileInput); } else { data.files = $.each($.makeArray(data.files), this._normalizeFile); } this._onAdd(null, data); }, // This method is exposed to the widget API and allows sending files // using the fileupload API. The data parameter accepts an object which // must have a files property and can contain additional options: // .fileupload('send', {files: filesList}); // The method returns a Promise object for the file upload call. send: function (data) { if (data && !this.options.disabled) { if (data.fileInput && !data.files) { data.files = this._getFileInputFiles(data.fileInput); } else { data.files = $.each($.makeArray(data.files), this._normalizeFile); } if (data.files.length) { return this._onSend(null, data); } } return this._getXHRPromise(false, data && data.context); } }); })); Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/jquery.iframe-transport.js0000644000000000000000000001763112237177136026640 0ustar 00000000000000/* * jQuery Iframe Transport Plugin 1.4 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ /*jslint unparam: true, nomen: true */ /*global define, window, document */ (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // Register as an anonymous AMD module: define(['jquery'], factory); } else { // Browser globals: factory(window.jQuery); } }(function ($) { 'use strict'; // Helper variable to create unique names for the transport iframes: var counter = 0; // The iframe transport accepts three additional options: // options.fileInput: a jQuery collection of file input fields // options.paramName: the parameter name for the file form data, // overrides the name property of the file input field(s), // can be a string or an array of strings. // options.formData: an array of objects with name and value properties, // equivalent to the return data of .serializeArray(), e.g.: // [{name: 'a', value: 1}, {name: 'b', value: 2}] $.ajaxTransport('iframe', function (options) { if (options.async && (options.type === 'POST' || options.type === 'GET')) { var form, iframe; return { send: function (_, completeCallback) { form = $('
      '); // javascript:false as initial iframe src // prevents warning popups on HTTPS in IE6. // IE versions below IE8 cannot set the name property of // elements that have already been added to the DOM, // so we set the name along with the iframe HTML markup: iframe = $( '' ).bind('load', function () { var fileInputClones, paramNames = $.isArray(options.paramName) ? options.paramName : [options.paramName]; iframe .unbind('load') .bind('load', function () { var response; // Wrap in a try/catch block to catch exceptions thrown // when trying to access cross-domain iframe contents: try { response = iframe.contents(); // Google Chrome and Firefox do not throw an // exception when calling iframe.contents() on // cross-domain requests, so we unify the response: if (!response.length || !response[0].firstChild) { throw new Error(); } } catch (e) { response = undefined; } // The complete callback returns the // iframe content document as response object: completeCallback( 200, 'success', {'iframe': response} ); // Fix for IE endless progress bar activity bug // (happens on form submits to iframe targets): $('') .appendTo(form); form.remove(); }); form .prop('target', iframe.prop('name')) .prop('action', options.url) .prop('method', options.type); if (options.formData) { $.each(options.formData, function (index, field) { $('') .prop('name', field.name) .val(field.value) .appendTo(form); }); } if (options.fileInput && options.fileInput.length && options.type === 'POST') { fileInputClones = options.fileInput.clone(); // Insert a clone for each file input field: options.fileInput.after(function (index) { return fileInputClones[index]; }); if (options.paramName) { options.fileInput.each(function (index) { $(this).prop( 'name', paramNames[index] || options.paramName ); }); } // Appending the file input fields to the hidden form // removes them from their original location: form .append(options.fileInput) .prop('enctype', 'multipart/form-data') // enctype must be set as encoding for IE: .prop('encoding', 'multipart/form-data'); } form.submit(); // Insert the file input fields at their original location // by replacing the clones with the originals: if (fileInputClones && fileInputClones.length) { options.fileInput.each(function (index, input) { var clone = $(fileInputClones[index]); $(input).prop('name', clone.prop('name')); clone.replaceWith(input); }); } }); form.append(iframe).appendTo(document.body); }, abort: function () { if (iframe) { // javascript:false as iframe src aborts the request // and prevents warning popups on HTTPS in IE6. // concat is used to avoid the "Script URL" JSLint error: iframe .unbind('load') .prop('src', 'javascript'.concat(':false;')); } if (form) { form.remove(); } } }; } }); // The iframe transport returns the iframe content document as response. // The following adds converters from iframe to text, json, html, and script: $.ajaxSetup({ converters: { 'iframe text': function (iframe) { return $(iframe[0].body).text(); }, 'iframe json': function (iframe) { return $.parseJSON($(iframe[0].body).text()); }, 'iframe html': function (iframe) { return $(iframe[0].body).html(); }, 'iframe script': function (iframe) { return $.globalEval($(iframe[0].body).text()); } } }); })); Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/locale.js0000644000000000000000000000143012237177136023252 0ustar 00000000000000/* * jQuery File Upload Plugin Localization Example 6.5.1 * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2012, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: * http://www.opensource.org/licenses/MIT */ /*global window */ window.locale = { "fileupload": { "errors": { "maxFileSize": "File is too big", "minFileSize": "File is too small", "acceptFileTypes": "Filetype not allowed", "maxNumberOfFiles": "Max number of files exceeded", "uploadedBytes": "Uploaded bytes exceed file size", "emptyResult": "Empty file upload result" }, "error": "Error", "start": "Start", "cancel": "Cancel", "destroy": "Delete" } }; Orthanc-0.7.2/OrthancExplorer/libs/jquery-file-upload/js/vendor/jquery.ui.widget.js0000644000000000000000000001616112237177136026534 0ustar 00000000000000/* * jQuery UI Widget 1.8.18+amd * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Widget */ (function (factory) { if (typeof define === "function" && define.amd) { // Register as an anonymous AMD module: define(["jquery"], factory); } else { // Browser globals: factory(jQuery); } }(function( $, undefined ) { // jQuery 1.4+ if ( $.cleanData ) { var _cleanData = $.cleanData; $.cleanData = function( elems ) { for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { try { $( elem ).triggerHandler( "remove" ); // http://bugs.jquery.com/ticket/8235 } catch( e ) {} } _cleanData( elems ); }; } else { var _remove = $.fn.remove; $.fn.remove = function( selector, keepData ) { return this.each(function() { if ( !keepData ) { if ( !selector || $.filter( selector, [ this ] ).length ) { $( "*", this ).add( [ this ] ).each(function() { try { $( this ).triggerHandler( "remove" ); // http://bugs.jquery.com/ticket/8235 } catch( e ) {} }); } } return _remove.call( $(this), selector, keepData ); }); }; } $.widget = function( name, base, prototype ) { var namespace = name.split( "." )[ 0 ], fullName; name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } // create selector for plugin $.expr[ ":" ][ fullName ] = function( elem ) { return !!$.data( elem, name ); }; $[ namespace ] = $[ namespace ] || {}; $[ namespace ][ name ] = function( options, element ) { // allow instantiation without initializing for simple inheritance if ( arguments.length ) { this._createWidget( options, element ); } }; var basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from // $.each( basePrototype, function( key, val ) { // if ( $.isPlainObject(val) ) { // basePrototype[ key ] = $.extend( {}, val ); // } // }); basePrototype.options = $.extend( true, {}, basePrototype.options ); $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { namespace: namespace, widgetName: name, widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, widgetBaseClass: fullName }, prototype ); $.widget.bridge( name, $[ namespace ][ name ] ); }; $.widget.bridge = function( name, object ) { $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string", args = Array.prototype.slice.call( arguments, 1 ), returnValue = this; // allow multiple hashes to be passed on init options = !isMethodCall && args.length ? $.extend.apply( null, [ true, options ].concat(args) ) : options; // prevent calls to internal methods if ( isMethodCall && options.charAt( 0 ) === "_" ) { return returnValue; } if ( isMethodCall ) { this.each(function() { var instance = $.data( this, name ), methodValue = instance && $.isFunction( instance[options] ) ? instance[ options ].apply( instance, args ) : instance; // TODO: add this back in 1.9 and use $.error() (see #5972) // if ( !instance ) { // throw "cannot call methods on " + name + " prior to initialization; " + // "attempted to call method '" + options + "'"; // } // if ( !$.isFunction( instance[options] ) ) { // throw "no such method '" + options + "' for " + name + " widget instance"; // } // var methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue; return false; } }); } else { this.each(function() { var instance = $.data( this, name ); if ( instance ) { instance.option( options || {} )._init(); } else { $.data( this, name, new object( options, this ) ); } }); } return returnValue; }; }; $.Widget = function( options, element ) { // allow instantiation without initializing for simple inheritance if ( arguments.length ) { this._createWidget( options, element ); } }; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", options: { disabled: false }, _createWidget: function( options, element ) { // $.widget.bridge stores the plugin instance, but we do it anyway // so that it's stored even before the _create function runs $.data( element, this.widgetName, this ); this.element = $( element ); this.options = $.extend( true, {}, this.options, this._getCreateOptions(), options ); var self = this; this.element.bind( "remove." + this.widgetName, function() { self.destroy(); }); this._create(); this._trigger( "create" ); this._init(); }, _getCreateOptions: function() { return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; }, _create: function() {}, _init: function() {}, destroy: function() { this.element .unbind( "." + this.widgetName ) .removeData( this.widgetName ); this.widget() .unbind( "." + this.widgetName ) .removeAttr( "aria-disabled" ) .removeClass( this.widgetBaseClass + "-disabled " + "ui-state-disabled" ); }, widget: function() { return this.element; }, option: function( key, value ) { var options = key; if ( arguments.length === 0 ) { // don't return a reference to the internal hash return $.extend( {}, this.options ); } if (typeof key === "string" ) { if ( value === undefined ) { return this.options[ key ]; } options = {}; options[ key ] = value; } this._setOptions( options ); return this; }, _setOptions: function( options ) { var self = this; $.each( options, function( key, value ) { self._setOption( key, value ); }); return this; }, _setOption: function( key, value ) { this.options[ key ] = value; if ( key === "disabled" ) { this.widget() [ value ? "addClass" : "removeClass"]( this.widgetBaseClass + "-disabled" + " " + "ui-state-disabled" ) .attr( "aria-disabled", value ); } return this; }, enable: function() { return this._setOption( "disabled", false ); }, disable: function() { return this._setOption( "disabled", true ); }, _trigger: function( type, event, data ) { var prop, orig, callback = this.options[ type ]; data = data || {}; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); // the original event may come from any element // so we need to reset the target on the new event event.target = this.element[ 0 ]; // copy original event properties over to the new event orig = event.originalEvent; if ( orig ) { for ( prop in orig ) { if ( !( prop in event ) ) { event[ prop ] = orig[ prop ]; } } } this.element.trigger( event, data ); return !( $.isFunction(callback) && callback.call( this.element[0], event, data ) === false || event.isDefaultPrevented() ); } }; })); Orthanc-0.7.2/OrthancExplorer/libs/jquery.blockui.js0000644000000000000000000003736012237177136020642 0ustar 00000000000000/*! * jQuery blockUI plugin * Version 2.39 (23-MAY-2011) * @requires jQuery v1.2.3 or later * * Examples at: http://malsup.com/jquery/block/ * Copyright (c) 2007-2010 M. Alsup * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Thanks to Amir-Hossein Sobhi for some excellent contributions! */ ;(function($) { if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) { alert('blockUI requires jQuery v1.2.3 or later! You are using v' + $.fn.jquery); return; } $.fn._fadeIn = $.fn.fadeIn; var noOp = function() {}; // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle // retarded userAgent strings on Vista) var mode = document.documentMode || 0; var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8); var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode; // global $ methods for blocking/unblocking the entire page $.blockUI = function(opts) { install(window, opts); }; $.unblockUI = function(opts) { remove(window, opts); }; // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl) $.growlUI = function(title, message, timeout, onClose) { var $m = $('
      '); if (title) $m.append('

      '+title+'

      '); if (message) $m.append('

      '+message+'

      '); if (timeout == undefined) timeout = 3000; $.blockUI({ message: $m, fadeIn: 700, fadeOut: 1000, centerY: false, timeout: timeout, showOverlay: false, onUnblock: onClose, css: $.blockUI.defaults.growlCSS }); }; // plugin method for blocking element content $.fn.block = function(opts) { return this.unblock({ fadeOut: 0 }).each(function() { if ($.css(this,'position') == 'static') this.style.position = 'relative'; if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' install(this, opts); }); }; // plugin method for unblocking element content $.fn.unblock = function(opts) { return this.each(function() { remove(this, opts); }); }; $.blockUI.version = 2.39; // 2nd generation blocking at no extra cost! // override these in your code to change the default behavior and style $.blockUI.defaults = { // message displayed when blocking (use null for no message) message: '

      Please wait...

      ', title: null, // title string; only used when theme == true draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded) theme: false, // set to true to use with jQuery UI themes // styles for the message when blocking; if you wish to disable // these and use an external stylesheet then do this in your code: // $.blockUI.defaults.css = {}; css: { padding: 0, margin: 0, width: '30%', top: '40%', left: '35%', textAlign: 'center', color: '#000', border: '3px solid #aaa', backgroundColor:'#fff', cursor: 'wait' }, // minimal style set used when themes are used themedCSS: { width: '30%', top: '40%', left: '35%' }, // styles for the overlay overlayCSS: { backgroundColor: '#000', opacity: 0.6, cursor: 'wait' }, // styles applied when using $.growlUI growlCSS: { width: '350px', top: '10px', left: '', right: '10px', border: 'none', padding: '5px', opacity: 0.6, cursor: 'default', color: '#fff', backgroundColor: '#000', '-webkit-border-radius': '10px', '-moz-border-radius': '10px', 'border-radius': '10px' }, // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w // (hat tip to Jorge H. N. de Vasconcelos) iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank', // force usage of iframe in non-IE browsers (handy for blocking applets) forceIframe: false, // z-index for the blocking overlay baseZ: 1000, // set these to true to have the message automatically centered centerX: true, // <-- only effects element blocking (page block controlled via css above) centerY: true, // allow body element to be stetched in ie6; this makes blocking look better // on "short" pages. disable if you wish to prevent changes to the body height allowBodyStretch: true, // enable if you want key and mouse events to be disabled for content that is blocked bindEvents: true, // be default blockUI will supress tab navigation from leaving blocking content // (if bindEvents is true) constrainTabKey: true, // fadeIn time in millis; set to 0 to disable fadeIn on block fadeIn: 200, // fadeOut time in millis; set to 0 to disable fadeOut on unblock fadeOut: 400, // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock timeout: 0, // disable if you don't want to show the overlay showOverlay: true, // if true, focus will be placed in the first available input field when // page blocking focusInput: true, // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity) applyPlatformOpacityRules: true, // callback method invoked when fadeIn has completed and blocking message is visible onBlock: null, // callback method invoked when unblocking has completed; the callback is // passed the element that has been unblocked (which is the window object for page // blocks) and the options that were passed to the unblock call: // onUnblock(element, options) onUnblock: null, // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493 quirksmodeOffsetHack: 4, // class name of the message block blockMsgClass: 'blockMsg' }; // private data and functions follow... var pageBlock = null; var pageBlockEls = []; function install(el, opts) { var full = (el == window); var msg = opts && opts.message !== undefined ? opts.message : undefined; opts = $.extend({}, $.blockUI.defaults, opts || {}); opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {}); var css = $.extend({}, $.blockUI.defaults.css, opts.css || {}); var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {}); msg = msg === undefined ? opts.message : msg; // remove the current block (if there is one) if (full && pageBlock) remove(window, {fadeOut:0}); // if an existing element is being used as the blocking content then we capture // its current place in the DOM (and current display style) so we can restore // it when we unblock if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) { var node = msg.jquery ? msg[0] : msg; var data = {}; $(el).data('blockUI.history', data); data.el = node; data.parent = node.parentNode; data.display = node.style.display; data.position = node.style.position; if (data.parent) data.parent.removeChild(node); } $(el).data('blockUI.onUnblock', opts.onUnblock); var z = opts.baseZ; // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform; // layer1 is the iframe layer which is used to supress bleed through of underlying content // layer2 is the overlay layer which has opacity and a wait cursor (by default) // layer3 is the message content that is displayed while blocking var lyr1 = ($.browser.msie || opts.forceIframe) ? $('') : $(''); var lyr2 = opts.theme ? $('') : $(''); var lyr3, s; if (opts.theme && full) { s = ''; } else if (opts.theme) { s = ''; } else if (full) { s = ''; } else { s = ''; } lyr3 = $(s); // if we have a message, style it if (msg) { if (opts.theme) { lyr3.css(themedCSS); lyr3.addClass('ui-widget-content'); } else lyr3.css(css); } // style the overlay if (!opts.theme && (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))) lyr2.css(opts.overlayCSS); lyr2.css('position', full ? 'fixed' : 'absolute'); // make iframe layer transparent in IE if ($.browser.msie || opts.forceIframe) lyr1.css('opacity',0.0); //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el); var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el); $.each(layers, function() { this.appendTo($par); }); if (opts.theme && opts.draggable && $.fn.draggable) { lyr3.draggable({ handle: '.ui-dialog-titlebar', cancel: 'li' }); } // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling) var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0); if (ie6 || expr) { // give body 100% height if (full && opts.allowBodyStretch && $.boxModel) $('html,body').css('height','100%'); // fix ie6 issue when blocked element has a border width if ((ie6 || !$.boxModel) && !full) { var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth'); var fixT = t ? '(0 - '+t+')' : 0; var fixL = l ? '(0 - '+l+')' : 0; } // simulate fixed position $.each([lyr1,lyr2,lyr3], function(i,o) { var s = o[0].style; s.position = 'absolute'; if (i < 2) { full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"') : s.setExpression('height','this.parentNode.offsetHeight + "px"'); full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"') : s.setExpression('width','this.parentNode.offsetWidth + "px"'); if (fixL) s.setExpression('left', fixL); if (fixT) s.setExpression('top', fixT); } else if (opts.centerY) { if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"'); s.marginTop = 0; } else if (!opts.centerY && full) { var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0; var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"'; s.setExpression('top',expression); } }); } // show the message if (msg) { if (opts.theme) lyr3.find('.ui-widget-content').append(msg); else lyr3.append(msg); if (msg.jquery || msg.nodeType) $(msg).show(); } if (($.browser.msie || opts.forceIframe) && opts.showOverlay) lyr1.show(); // opacity is zero if (opts.fadeIn) { var cb = opts.onBlock ? opts.onBlock : noOp; var cb1 = (opts.showOverlay && !msg) ? cb : noOp; var cb2 = msg ? cb : noOp; if (opts.showOverlay) lyr2._fadeIn(opts.fadeIn, cb1); if (msg) lyr3._fadeIn(opts.fadeIn, cb2); } else { if (opts.showOverlay) lyr2.show(); if (msg) lyr3.show(); if (opts.onBlock) opts.onBlock(); } // bind key and mouse events bind(1, el, opts); if (full) { pageBlock = lyr3[0]; pageBlockEls = $(':input:enabled:visible',pageBlock); if (opts.focusInput) setTimeout(focus, 20); } else center(lyr3[0], opts.centerX, opts.centerY); if (opts.timeout) { // auto-unblock var to = setTimeout(function() { full ? $.unblockUI(opts) : $(el).unblock(opts); }, opts.timeout); $(el).data('blockUI.timeout', to); } }; // remove the block function remove(el, opts) { var full = (el == window); var $el = $(el); var data = $el.data('blockUI.history'); var to = $el.data('blockUI.timeout'); if (to) { clearTimeout(to); $el.removeData('blockUI.timeout'); } opts = $.extend({}, $.blockUI.defaults, opts || {}); bind(0, el, opts); // unbind events if (opts.onUnblock === null) { opts.onUnblock = $el.data('blockUI.onUnblock'); $el.removeData('blockUI.onUnblock'); } var els; if (full) // crazy selector to handle odd field errors in ie6/7 els = $('body').children().filter('.blockUI').add('body > .blockUI'); else els = $('.blockUI', el); if (full) pageBlock = pageBlockEls = null; if (opts.fadeOut) { els.fadeOut(opts.fadeOut); setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut); } else reset(els, data, opts, el); }; // move blocking element back into the DOM where it started function reset(els,data,opts,el) { els.each(function(i,o) { // remove via DOM calls so we don't lose event handlers if (this.parentNode) this.parentNode.removeChild(this); }); if (data && data.el) { data.el.style.display = data.display; data.el.style.position = data.position; if (data.parent) data.parent.appendChild(data.el); $(el).removeData('blockUI.history'); } if (typeof opts.onUnblock == 'function') opts.onUnblock(el,opts); }; // bind/unbind the handler function bind(b, el, opts) { var full = el == window, $el = $(el); // don't bother unbinding if there is nothing to unbind if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked'))) return; if (!full) $el.data('blockUI.isBlocked', b); // don't bind events when overlay is not in use or if bindEvents is false if (!opts.bindEvents || (b && !opts.showOverlay)) return; // bind anchors and inputs for mouse and key events var events = 'mousedown mouseup keydown keypress'; b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler); // former impl... // var $e = $('a,:input'); // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler); }; // event handler to suppress keyboard/mouse events when blocking function handler(e) { // allow tab navigation (conditionally) if (e.keyCode && e.keyCode == 9) { if (pageBlock && e.data.constrainTabKey) { var els = pageBlockEls; var fwd = !e.shiftKey && e.target === els[els.length-1]; var back = e.shiftKey && e.target === els[0]; if (fwd || back) { setTimeout(function(){focus(back)},10); return false; } } } var opts = e.data; // allow events within the message content if ($(e.target).parents('div.' + opts.blockMsgClass).length > 0) return true; // allow events for content that is not being blocked return $(e.target).parents().children().filter('div.blockUI').length == 0; }; function focus(back) { if (!pageBlockEls) return; var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0]; if (e) e.focus(); }; function center(el, x, y) { var p = el.parentNode, s = el.style; var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth'); var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth'); if (x) s.left = l > 0 ? (l+'px') : '0'; if (y) s.top = t > 0 ? (t+'px') : '0'; }; function sz(el, p) { return parseInt($.css(el,p))||0; }; })(jQuery); Orthanc-0.7.2/OrthancExplorer/libs/jquery.mobile-1.1.0.min.css0000644000000000000000000016643612237177136022061 0ustar 00000000000000/*! jQuery Mobile v1.1.0 db342b1f315c282692791aa870455901fdb46a55 jquerymobile.com | jquery.org/license */ .ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:bold;text-shadow:0 -1px 1px #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#111));background-image:-webkit-linear-gradient(#3c3c3c,#111);background-image:-moz-linear-gradient(#3c3c3c,#111);background-image:-ms-linear-gradient(#3c3c3c,#111);background-image:-o-linear-gradient(#3c3c3c,#111);background-image:linear-gradient(#3c3c3c,#111)}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a .ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-a .ui-link:hover{color:#2489ce}.ui-bar-a .ui-link:active{color:#2489ce}.ui-bar-a .ui-link:visited{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 1px #111;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#222));background-image:-webkit-linear-gradient(#444,#222);background-image:-moz-linear-gradient(#444,#222);background-image:-ms-linear-gradient(#444,#222);background-image:-o-linear-gradient(#444,#222);background-image:linear-gradient(#444,#222)}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:bold}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-body-a .ui-link:visited{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:bold;color:#fff;text-shadow:0 1px 1px #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#2d2d2d));background-image:-webkit-linear-gradient(#444,#2d2d2d);background-image:-moz-linear-gradient(#444,#2d2d2d);background-image:-ms-linear-gradient(#444,#2d2d2d);background-image:-o-linear-gradient(#444,#2d2d2d);background-image:linear-gradient(#444,#2d2d2d)}.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:bold;color:#fff;text-shadow:0 1px 1px #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#383838));background-image:-webkit-linear-gradient(#555,#383838);background-image:-moz-linear-gradient(#555,#383838);background-image:-ms-linear-gradient(#555,#383838);background-image:-o-linear-gradient(#555,#383838);background-image:linear-gradient(#555,#383838)}.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:bold;color:#fff;text-shadow:0 1px 1px #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#202020),to(#2c2c2c));background-image:-webkit-linear-gradient(#202020,#2c2c2c);background-image:-moz-linear-gradient(#202020,#2c2c2c);background-image:-ms-linear-gradient(#202020,#2c2c2c);background-image:-o-linear-gradient(#202020,#2c2c2c);background-image:linear-gradient(#202020,#2c2c2c)}.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:bold;text-shadow:0 1px 1px #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#497bae));background-image:-webkit-linear-gradient(#6facd5,#497bae);background-image:-moz-linear-gradient(#6facd5,#497bae);background-image:-ms-linear-gradient(#6facd5,#497bae);background-image:-o-linear-gradient(#6facd5,#497bae);background-image:linear-gradient(#6facd5,#497bae)}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b .ui-link{color:#ddf0f8;font-weight:bold}.ui-bar-b .ui-link:hover{color:#ddf0f8}.ui-bar-b .ui-link:active{color:#ddf0f8}.ui-bar-b .ui-link:visited{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#ccc));background-image:-webkit-linear-gradient(#ddd,#ccc);background-image:-moz-linear-gradient(#ddd,#ccc);background-image:-ms-linear-gradient(#ddd,#ccc);background-image:-o-linear-gradient(#ddd,#ccc);background-image:linear-gradient(#ddd,#ccc)}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:bold}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-body-b .ui-link:visited{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:bold;color:#fff;text-shadow:0 1px 1px #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from(#5f9cc5),to(#396b9e));background-image:-webkit-linear-gradient(#5f9cc5,#396b9e);background-image:-moz-linear-gradient(#5f9cc5,#396b9e);background-image:-ms-linear-gradient(#5f9cc5,#396b9e);background-image:-o-linear-gradient(#5f9cc5,#396b9e);background-image:linear-gradient(#5f9cc5,#396b9e)}.ui-btn-up-b a.ui-link-inherit{color:#fff}.ui-btn-hover-b{border:1px solid #00415e;background:#4b88b6;font-weight:bold;color:#fff;text-shadow:0 1px 1px #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#4272a4));background-image:-webkit-linear-gradient(#6facd5,#4272a4);background-image:-moz-linear-gradient(#6facd5,#4272a4);background-image:-ms-linear-gradient(#6facd5,#4272a4);background-image:-o-linear-gradient(#6facd5,#4272a4);background-image:linear-gradient(#6facd5,#4272a4)}.ui-btn-hover-b a.ui-link-inherit{color:#fff}.ui-btn-down-b{border:1px solid #225377;background:#4e89c5;font-weight:bold;color:#fff;text-shadow:0 1px 1px #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from(#295b8e),to(#3e79b5));background-image:-webkit-linear-gradient(#295b8e,#3e79b5);background-image:-moz-linear-gradient(#295b8e,#3e79b5);background-image:-ms-linear-gradient(#295b8e,#3e79b5);background-image:-o-linear-gradient(#295b8e,#3e79b5);background-image:linear-gradient(#295b8e,#3e79b5)}.ui-btn-down-b a.ui-link-inherit{color:#fff}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-c{border:1px solid #b3b3b3;background:#eee;color:#3e3e3e;font-weight:bold;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f0f0f0),to(#ddd));background-image:-webkit-linear-gradient(#f0f0f0,#ddd);background-image:-moz-linear-gradient(#f0f0f0,#ddd);background-image:-ms-linear-gradient(#f0f0f0,#ddd);background-image:-o-linear-gradient(#f0f0f0,#ddd);background-image:linear-gradient(#f0f0f0,#ddd)}.ui-bar-c .ui-link-inherit{color:#3e3e3e}.ui-bar-c .ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-c .ui-link:hover{color:#2489ce}.ui-bar-c .ui-link:active{color:#2489ce}.ui-bar-c .ui-link:visited{color:#2489ce}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c,.ui-overlay-c{border:1px solid #aaa;color:#333;text-shadow:0 1px 0 #fff;background:#f9f9f9;background-image:-webkit-gradient(linear,left top,left bottom,from(#f9f9f9),to(#eee));background-image:-webkit-linear-gradient(#f9f9f9,#eee);background-image:-moz-linear-gradient(#f9f9f9,#eee);background-image:-ms-linear-gradient(#f9f9f9,#eee);background-image:-o-linear-gradient(#f9f9f9,#eee);background-image:linear-gradient(#f9f9f9,#eee)}.ui-overlay-c{background-image:none;border-width:0}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c .ui-link-inherit{color:#333}.ui-body-c .ui-link{color:#2489ce;font-weight:bold}.ui-body-c .ui-link:hover{color:#2489ce}.ui-body-c .ui-link:active{color:#2489ce}.ui-body-c .ui-link:visited{color:#2489ce}.ui-btn-up-c{border:1px solid #ccc;background:#eee;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f1f1f1));background-image:-webkit-linear-gradient(#fff,#f1f1f1);background-image:-moz-linear-gradient(#fff,#f1f1f1);background-image:-ms-linear-gradient(#fff,#f1f1f1);background-image:-o-linear-gradient(#fff,#f1f1f1);background-image:linear-gradient(#fff,#f1f1f1)}.ui-btn-up-c a.ui-link-inherit{color:#2f3e46}.ui-btn-hover-c{border:1px solid #bbb;background:#dfdfdf;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f6f6f6),to(#e0e0e0));background-image:-webkit-linear-gradient(#f9f9f9,#e0e0e0);background-image:-moz-linear-gradient(#f6f6f6,#e0e0e0);background-image:-ms-linear-gradient(#f6f6f6,#e0e0e0);background-image:-o-linear-gradient(#f6f6f6,#e0e0e0);background-image:linear-gradient(#f6f6f6,#e0e0e0)}.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46}.ui-btn-down-c{border:1px solid #bbb;background:#d6d6d6;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#d0d0d0),to(#dfdfdf));background-image:-webkit-linear-gradient(#d0d0d0,#dfdfdf);background-image:-moz-linear-gradient(#d0d0d0,#dfdfdf);background-image:-ms-linear-gradient(#d0d0d0,#dfdfdf);background-image:-o-linear-gradient(#d0d0d0,#dfdfdf);background-image:linear-gradient(#d0d0d0,#dfdfdf)}.ui-btn-down-c a.ui-link-inherit{color:#2f3e46}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-d{border:1px solid #bbb;background:#bbb;color:#333;text-shadow:0 1px 0 #eee;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#bbb));background-image:-webkit-linear-gradient(#ddd,#bbb);background-image:-moz-linear-gradient(#ddd,#bbb);background-image:-ms-linear-gradient(#ddd,#bbb);background-image:-o-linear-gradient(#ddd,#bbb);background-image:linear-gradient(#ddd,#bbb)}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-d .ui-link-inherit{color:#333}.ui-bar-d .ui-link{color:#2489ce;font-weight:bold}.ui-bar-d .ui-link:hover{color:#2489ce}.ui-bar-d .ui-link:active{color:#2489ce}.ui-bar-d .ui-link:visited{color:#2489ce}.ui-body-d,.ui-overlay-d{border:1px solid #bbb;color:#333;text-shadow:0 1px 0 #fff;background:#fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#fff));background-image:-webkit-linear-gradient(#fff,#fff);background-image:-moz-linear-gradient(#fff,#fff);background-image:-ms-linear-gradient(#fff,#fff);background-image:-o-linear-gradient(#fff,#fff);background-image:linear-gradient(#fff,#fff)}.ui-overlay-d{background-image:none;border-width:0}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif}.ui-body-d .ui-link-inherit{color:#333}.ui-body-d .ui-link{color:#2489ce;font-weight:bold}.ui-body-d .ui-link:hover{color:#2489ce}.ui-body-d .ui-link:active{color:#2489ce}.ui-body-d .ui-link:visited{color:#2489ce}.ui-btn-up-d{border:1px solid #bbb;background:#fff;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fafafa),to(#f6f6f6));background-image:-webkit-linear-gradient(#fafafa,#f6f6f6);background-image:-moz-linear-gradient(#fafafa,#f6f6f6);background-image:-ms-linear-gradient(#fafafa,#f6f6f6);background-image:-o-linear-gradient(#fafafa,#f6f6f6);background-image:linear-gradient(#fafafa,#f6f6f6)}.ui-btn-up-d a.ui-link-inherit{color:#333}.ui-btn-hover-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#333;cursor:pointer;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#eee),to(#fff));background-image:-webkit-linear-gradient(#eee,#fff);background-image:-moz-linear-gradient(#eee,#fff);background-image:-ms-linear-gradient(#eee,#fff);background-image:-o-linear-gradient(#eee,#fff);background-image:linear-gradient(#eee,#fff)}.ui-btn-hover-d a.ui-link-inherit{color:#333}.ui-btn-down-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#e5e5e5),to(#f2f2f2));background-image:-webkit-linear-gradient(#e5e5e5,#f2f2f2);background-image:-moz-linear-gradient(#e5e5e5,#f2f2f2);background-image:-ms-linear-gradient(#e5e5e5,#f2f2f2);background-image:-o-linear-gradient(#e5e5e5,#f2f2f2);background-image:linear-gradient(#e5e5e5,#f2f2f2)}.ui-btn-down-d a.ui-link-inherit{color:#333}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-e{border:1px solid #f7c942;background:#fadb4e;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fceda7),to(#fbef7e));background-image:-webkit-linear-gradient(#fceda7,#fbef7e);background-image:-moz-linear-gradient(#fceda7,#fbef7e);background-image:-ms-linear-gradient(#fceda7,#fbef7e);background-image:-o-linear-gradient(#fceda7,#fbef7e);background-image:linear-gradient(#fceda7,#fbef7e)}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-e button{font-family:Helvetica,Arial,sans-serif}.ui-bar-e .ui-link-inherit{color:#333}.ui-bar-e .ui-link{color:#2489ce;font-weight:bold}.ui-bar-e .ui-link:hover{color:#2489ce}.ui-bar-e .ui-link:active{color:#2489ce}.ui-bar-e .ui-link:visited{color:#2489ce}.ui-body-e,.ui-overlay-e{border:1px solid #f7c942;color:#222;text-shadow:0 1px 0 #fff;background:#fff9df;background-image:-webkit-gradient(linear,left top,left bottom,from(#fffadf),to(#fff3a5));background-image:-webkit-linear-gradient(#fffadf,#fff3a5);background-image:-moz-linear-gradient(#fffadf,#fff3a5);background-image:-ms-linear-gradient(#fffadf,#fff3a5);background-image:-o-linear-gradient(#fffadf,#fff3a5);background-image:linear-gradient(#fffadf,#fff3a5)}.ui-overlay-e{background-image:none;border-width:0}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif}.ui-body-e .ui-link-inherit{color:#333}.ui-body-e .ui-link{color:#2489ce;font-weight:bold}.ui-body-e .ui-link:hover{color:#2489ce}.ui-body-e .ui-link:active{color:#2489ce}.ui-body-e .ui-link:visited{color:#2489ce}.ui-btn-up-e{border:1px solid #f4c63f;background:#fadb4e;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffefaa),to(#ffe155));background-image:-webkit-linear-gradient(#ffefaa,#ffe155);background-image:-moz-linear-gradient(#ffefaa,#ffe155);background-image:-ms-linear-gradient(#ffefaa,#ffe155);background-image:-o-linear-gradient(#ffefaa,#ffe155);background-image:linear-gradient(#ffefaa,#ffe155)}.ui-btn-up-e a.ui-link-inherit{color:#222}.ui-btn-hover-e{border:1px solid #f2c43d;background:#fbe26f;font-weight:bold;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff5ba),to(#fbdd52));background-image:-webkit-linear-gradient(#fff5ba,#fbdd52);background-image:-moz-linear-gradient(#fff5ba,#fbdd52);background-image:-ms-linear-gradient(#fff5ba,#fbdd52);background-image:-o-linear-gradient(#fff5ba,#fbdd52);background-image:linear-gradient(#fff5ba,#fbdd52)}.ui-btn-hover-e a.ui-link-inherit{color:#333}.ui-btn-down-e{border:1px solid #f2c43d;background:#fceda7;font-weight:bold;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f8d94c),to(#fadb4e));background-image:-webkit-linear-gradient(#f8d94c,#fadb4e);background-image:-moz-linear-gradient(#f8d94c,#fadb4e);background-image:-ms-linear-gradient(#f8d94c,#fadb4e);background-image:-o-linear-gradient(#f8d94c,#fadb4e);background-image:linear-gradient(#f8d94c,#fadb4e)}.ui-btn-down-e a.ui-link-inherit{color:#333}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif;text-decoration:none}a.ui-link-inherit{text-decoration:none!important}.ui-btn-active{border:1px solid #2373a5;background:#5393c5;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 1px 1px #3373a5;text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,from(#5393c5),to(#6facd5));background-image:-webkit-linear-gradient(#5393c5,#6facd5);background-image:-moz-linear-gradient(#5393c5,#6facd5);background-image:-ms-linear-gradient(#5393c5,#6facd5);background-image:-o-linear-gradient(#5393c5,#6facd5);background-image:linear-gradient(#5393c5,#6facd5);font-family:Helvetica,Arial,sans-serif}.ui-btn-active a.ui-link-inherit{color:#fff}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3)}.ui-corner-tl{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em}.ui-corner-tr{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bl{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-br{-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-top{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bottom{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-right{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-left{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-all{-moz-border-radius:.6em;-webkit-border-radius:.6em;border-radius:.6em}.ui-corner-none{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.ui-br{border-bottom:#828282;border-bottom:rgba(130,130,130,.3);border-bottom-width:1px;border-bottom-style:solid}.ui-disabled{opacity:.3}.ui-disabled,.ui-disabled a{cursor:default!important;pointer-events:none}.ui-disabled .ui-btn-text{-ms-filter:"alpha(opacity=30)";filter:alpha(opacity=30);zoom:1}.ui-icon,.ui-icon-searchfield:after{background:#666;background:rgba(0,0,0,.4);background-image:url(images/icons-18-white.png);background-repeat:no-repeat;-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-alt{background:#fff;background:rgba(255,255,255,.3);background-image:url(images/icons-18-black.png);background-repeat:no-repeat}@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:240dpi){.ui-icon-plus,.ui-icon-minus,.ui-icon-delete,.ui-icon-arrow-r,.ui-icon-arrow-l,.ui-icon-arrow-u,.ui-icon-arrow-d,.ui-icon-check,.ui-icon-gear,.ui-icon-refresh,.ui-icon-forward,.ui-icon-back,.ui-icon-grid,.ui-icon-star,.ui-icon-alert,.ui-icon-info,.ui-icon-home,.ui-icon-search,.ui-icon-searchfield:after,.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-image:url(images/icons-36-white.png);-moz-background-size:776px 18px;-o-background-size:776px 18px;-webkit-background-size:776px 18px;background-size:776px 18px}.ui-icon-alt{background-image:url(images/icons-36-black.png)}}.ui-icon-plus{background-position:-0 50%}.ui-icon-minus{background-position:-36px 50%}.ui-icon-delete{background-position:-72px 50%}.ui-icon-arrow-r{background-position:-108px 50%}.ui-icon-arrow-l{background-position:-144px 50%}.ui-icon-arrow-u{background-position:-180px 50%}.ui-icon-arrow-d{background-position:-216px 50%}.ui-icon-check{background-position:-252px 50%}.ui-icon-gear{background-position:-288px 50%}.ui-icon-refresh{background-position:-324px 50%}.ui-icon-forward{background-position:-360px 50%}.ui-icon-back{background-position:-396px 50%}.ui-icon-grid{background-position:-432px 50%}.ui-icon-star{background-position:-468px 50%}.ui-icon-alert{background-position:-504px 50%}.ui-icon-info{background-position:-540px 50%}.ui-icon-home{background-position:-576px 50%}.ui-icon-search,.ui-icon-searchfield:after{background-position:-612px 50%}.ui-icon-checkbox-off{background-position:-684px 50%}.ui-icon-checkbox-on{background-position:-648px 50%}.ui-icon-radio-off{background-position:-756px 50%}.ui-icon-radio-on{background-position:-720px 50%}.ui-checkbox .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}.ui-icon-checkbox-off,.ui-icon-radio-off{background-color:transparent}.ui-checkbox-on .ui-icon,.ui-radio-on .ui-icon{background-color:#4596ce}.ui-icon-loading{background:url(images/ajax-loader.gif);background-size:46px 46px}.ui-btn-corner-tl{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em}.ui-btn-corner-tr{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bl{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-br{-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-top{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bottom{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-right{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-left{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-all{-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em}.ui-corner-tl,.ui-corner-tr,.ui-corner-bl,.ui-corner-br,.ui-corner-top,.ui-corner-bottom,.ui-corner-right,.ui-corner-left,.ui-corner-all,.ui-btn-corner-tl,.ui-btn-corner-tr,.ui-btn-corner-bl,.ui-btn-corner-br,.ui-btn-corner-top,.ui-btn-corner-bottom,.ui-btn-corner-right,.ui-btn-corner-left,.ui-btn-corner-all{-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.ui-overlay{background:#666;opacity:.5;filter:Alpha(Opacity=50);position:absolute;width:100%;height:100%}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-shadow{-moz-box-shadow:0 1px 4px rgba(0,0,0,.3);-webkit-box-shadow:0 1px 4px rgba(0,0,0,.3);box-shadow:0 1px 4px rgba(0,0,0,.3)}.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2)}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4);box-shadow:0 1px 0 rgba(255,255,255,.4)}.ui-btn:focus{outline:0}.ui-focus,.ui-btn:focus{-moz-box-shadow:0 0 12px #387bbe;-webkit-box-shadow:0 0 12px #387bbe;box-shadow:0 0 12px #387bbe}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}.ui-mobile-nosupport-boxshadow .ui-focus,.ui-mobile-nosupport-boxshadow .ui-btn:focus{outline-width:1px;outline-style:dotted}.ui-mobile,.ui-mobile body{height:99.9%}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border-width:0}.ui-mobile-viewport{margin:0;overflow-x:visible;-webkit-text-size-adjust:none;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ui-mobile-viewport,div.ui-mobile-viewport{overflow-x:hidden}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-mobile .ui-page-active{display:block;overflow:visible}.ui-page{outline:0}@media screen and (orientation:portrait){.ui-mobile,.ui-mobile .ui-page{min-height:420px}}@media screen and (orientation:landscape){.ui-mobile,.ui-mobile .ui-page{min-height:300px}}.ui-loading .ui-loader{display:block}.ui-loader{display:none;z-index:9999999;position:fixed;top:50%;box-shadow:0 1px 1px -1px #fff;left:50%;border:0}.ui-loader-default{background:0;opacity:.18;width:46px;height:46px;margin-left:-23px;margin-top:-23px}.ui-loader-verbose{width:200px;opacity:.88;height:auto;margin-left:-110px;margin-top:-43px;padding:10px}.ui-loader-default h1{font-size:0;width:0;height:0;overflow:hidden}.ui-loader-verbose h1{font-size:16px;margin:0;text-align:center}.ui-loader .ui-icon{background-color:#000;display:block;margin:0;width:44px;height:44px;padding:1px;-webkit-border-radius:36px;-moz-border-radius:36px;border-radius:36px}.ui-loader-verbose .ui-icon{margin:0 auto 10px;opacity:.75}.ui-loader-textonly{padding:15px;margin-left:-115px}.ui-loader-textonly .ui-icon{display:none}.ui-loader-fakefix{position:absolute}.ui-mobile-rendering>*{visibility:hidden}.ui-bar,.ui-body{position:relative;padding:.4em 15px;overflow:hidden;display:block;clear:both}.ui-bar{font-size:16px;margin:0}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:16px;display:inline-block}.ui-header,.ui-footer{position:relative;border-left-width:0;border-right-width:0}.ui-header .ui-btn-left,.ui-header .ui-btn-right,.ui-footer .ui-btn-left,.ui-footer .ui-btn-right{position:absolute;top:3px}.ui-header .ui-btn-left,.ui-footer .ui-btn-left{left:5px}.ui-header .ui-btn-right,.ui-footer .ui-btn-right{right:5px}.ui-footer .ui-btn-icon-notext,.ui-header .ui-btn-icon-notext{top:6px}.ui-header .ui-title,.ui-footer .ui-title{min-height:1.1em;text-align:center;font-size:16px;display:block;margin:.6em 30% .8em;padding:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-footer .ui-title{margin:.6em 15px .8em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-icon{width:18px;height:18px}.ui-nojs{position:absolute;left:-9999px}.ui-hide-label label,.ui-hidden-accessible{position:absolute!important;left:-9999px;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden}.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms}.out{-webkit-animation-timing-function:ease-in;-webkit-animation-duration:225ms;-moz-animation-timing-function:ease-in;-moz-animation-duration:225}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.out{opacity:0;-webkit-animation-duration:125ms;-webkit-animation-name:fadeout;-moz-animation-duration:125ms;-moz-animation-name:fadeout}.fade.in{opacity:1;-webkit-animation-duration:225ms;-webkit-animation-name:fadein;-moz-animation-duration:225ms;-moz-animation-name:fadein}.pop{-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);-moz-transform:scale(1);opacity:1;-webkit-animation-name:popin;-moz-animation-name:popin;-webkit-animation-duration:350ms;-moz-animation-duration:350ms}.pop.out{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;opacity:0;-webkit-animation-duration:100ms;-moz-animation-duration:100ms}.pop.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein}.pop.out.reverse{-webkit-transform:scale(.8);-moz-transform:scale(.8);-webkit-animation-name:popout;-moz-animation-name:popout}@-webkit-keyframes popin{from{-webkit-transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes popin{from{-moz-transform:scale(.8);opacity:0}to{-moz-transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.8);opacity:0}}@-moz-keyframes popout{from{-moz-transform:scale(1);opacity:1}to{-moz-transform:scale(.8);opacity:0}}@-webkit-keyframes slideinfromright{from{-webkit-transform:translateX(100%)}to{-webkit-transform:translateX(0)}}@-moz-keyframes slideinfromright{from{-moz-transform:translateX(100%)}to{-moz-transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translateX(-100%)}to{-webkit-transform:translateX(0)}}@-moz-keyframes slideinfromleft{from{-moz-transform:translateX(-100%)}to{-moz-transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(-100%)}}@-moz-keyframes slideouttoleft{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(100%)}}@-moz-keyframes slideouttoright{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(100%)}}.slide.out,.slide.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms}.slide.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft}.slide.in{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromright;-moz-transform:translateX(0);-moz-animation-name:slideinfromright}.slide.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright}.slide.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromleft;-moz-transform:translateX(0);-moz-animation-name:slideinfromleft}.slidefade.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;-webkit-animation-duration:225ms;-moz-animation-duration:225ms}.slidefade.in{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-moz-transform:translateX(0);-moz-animation-name:fadein;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}.slidefade.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}.slidefade.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-moz-transform:translateX(0);-moz-animation-name:fadein;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}.slidedown.out{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-duration:100ms}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;-moz-transform:translateY(0);-moz-animation-name:slideinfromtop;-webkit-animation-duration:250ms;-moz-animation-duration:250ms}.slidedown.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-duration:150ms}.slidedown.out.reverse{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-webkit-animation-name:slideouttotop;-moz-animation-name:slideouttotop;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfromtop{from{-moz-transform:translateY(-100%)}to{-moz-transform:translateY(0)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-moz-keyframes slideouttotop{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(-100%)}}.slideup.out{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-duration:100ms}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;-moz-transform:translateY(0);-moz-animation-name:slideinfrombottom;-webkit-animation-duration:250ms;-moz-animation-duration:250ms}.slideup.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-duration:150ms}.slideup.out.reverse{-webkit-transform:translateY(100%);-moz-transform:translateY(100%);-webkit-animation-name:slideouttobottom;-moz-animation-name:slideouttobottom;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfrombottom{from{-moz-transform:translateY(100%)}to{-moz-transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-moz-keyframes slideouttobottom{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(100%)}}.viewport-flip{-webkit-perspective:1000;-moz-perspective:1000;position:absolute}.flip{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-moz-backface-visibility:hidden;-moz-transform:translateX(0)}.flip.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:175ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:175ms}.flip.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:225ms;-moz-animation-name:flipintoright;-moz-animation-duration:225ms}.flip.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright}.flip.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}.viewport-turn{-webkit-perspective:1000;-moz-perspective:1000;position:absolute}.turn{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-webkit-transform-origin:0 0;-moz-backface-visibility:hidden;-moz-transform:translateX(0);-moz-transform-origin:0 0}.turn.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-webkit-animation-duration:125ms;-moz-animation-duration:125ms}.turn.in{-webkit-animation-name:flipintoright;-moz-animation-name:flipintoright;-webkit-animation-duration:250ms;-moz-animation-duration:250ms}.turn.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright}.turn.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}.flow{-webkit-transform-origin:50% 30%;-moz-transform-origin:50% 30%;-webkit-box-shadow:0 0 20px rgba(0,0,0,.4);-moz-box-shadow:0 0 20px rgba(0,0,0,.4)}.ui-dialog.flow{-webkit-transform-origin:none;-moz-transform-origin:none;-webkit-box-shadow:none;-moz-box-shadow:none}.flow.out{-webkit-transform:translateX(-100%) scale(.7);-webkit-animation-name:flowouttoleft;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(-100%) scale(.7);-moz-animation-name:flowouttoleft;-moz-animation-timing-function:ease;-moz-animation-duration:350ms}.flow.in{-webkit-transform:translateX(0) scale(1);-webkit-animation-name:flowinfromright;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(0) scale(1);-moz-animation-name:flowinfromright;-moz-animation-timing-function:ease;-moz-animation-duration:350ms}.flow.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:flowouttoright;-moz-transform:translateX(100%);-moz-animation-name:flowouttoright}.flow.in.reverse{-webkit-animation-name:flowinfromleft;-moz-animation-name:flowinfromleft}@-webkit-keyframes flowouttoleft{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(-100%) scale(.7)}}@-moz-keyframes flowouttoleft{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(-100%) scale(.7)}}@-webkit-keyframes flowouttoright{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(100%) scale(.7)}}@-moz-keyframes flowouttoright{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(100%) scale(.7)}}@-webkit-keyframes flowinfromleft{0%{-webkit-transform:translateX(-100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromleft{0%{-moz-transform:translateX(-100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@-webkit-keyframes flowinfromright{0%{-webkit-transform:translateX(100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromright{0%{-moz-transform:translateX(100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left;min-height:1px}.ui-grid-solo .ui-block-a{width:100%;float:none}.ui-grid-a .ui-block-a,.ui-grid-a .ui-block-b{width:50%}.ui-grid-a .ui-block-a{clear:left}.ui-grid-b .ui-block-a,.ui-grid-b .ui-block-b,.ui-grid-b .ui-block-c{width:33.333%}.ui-grid-b .ui-block-a{clear:left}.ui-grid-c .ui-block-a,.ui-grid-c .ui-block-b,.ui-grid-c .ui-block-c,.ui-grid-c .ui-block-d{width:25%}.ui-grid-c .ui-block-a{clear:left}.ui-grid-d .ui-block-a,.ui-grid-d .ui-block-b,.ui-grid-d .ui-block-c,.ui-grid-d .ui-block-d,.ui-grid-d .ui-block-e{width:20%}.ui-grid-d .ui-block-a{clear:left}.ui-header-fixed,.ui-footer-fixed{left:0;right:0;width:100%;position:fixed;z-index:1000}.ui-header-fixed{top:0}.ui-footer-fixed{bottom:0}.ui-header-fullscreen,.ui-footer-fullscreen{opacity:.9}.ui-page-header-fixed{padding-top:2.5em}.ui-page-footer-fixed{padding-bottom:3em}.ui-page-header-fullscreen .ui-content,.ui-page-footer-fullscreen .ui-content{padding:0}.ui-fixed-hidden{position:absolute}.ui-page-header-fullscreen .ui-fixed-hidden,.ui-page-footer-fullscreen .ui-fixed-hidden{left:-99999em}.ui-header-fixed .ui-btn,.ui-footer-fixed .ui-btn{z-index:10}.ui-navbar{overflow:hidden}.ui-navbar ul,.ui-navbar-expanded ul{list-style:none;padding:0;margin:0;position:relative;display:block;border:0}.ui-navbar-collapsed ul{float:left;width:75%;margin-right:-2px}.ui-navbar-collapsed .ui-navbar-toggle{float:left;width:25%}.ui-navbar li.ui-navbar-truncate{position:absolute;left:-9999px;top:-9999px}.ui-navbar li .ui-btn,.ui-navbar .ui-navbar-toggle .ui-btn{display:block;font-size:12px;text-align:center;margin:0;border-right-width:0;max-width:100%}.ui-navbar li .ui-btn{margin-right:-1px}.ui-navbar li .ui-btn:last-child{margin-right:0}.ui-header .ui-navbar li .ui-btn,.ui-header .ui-navbar .ui-navbar-toggle .ui-btn,.ui-footer .ui-navbar li .ui-btn,.ui-footer .ui-navbar .ui-navbar-toggle .ui-btn{border-top-width:0;border-bottom-width:0}.ui-navbar .ui-btn-inner{padding-left:2px;padding-right:2px}.ui-navbar-noicons li .ui-btn .ui-btn-inner,.ui-navbar-noicons .ui-navbar-toggle .ui-btn-inner{padding-top:.8em;padding-bottom:.9em}.ui-navbar-expanded .ui-btn{margin:0;font-size:14px}.ui-navbar-expanded .ui-btn-inner{padding-left:5px;padding-right:5px}.ui-navbar-expanded .ui-btn-icon-top .ui-btn-inner{padding:45px 5px 15px;text-align:center}.ui-navbar-expanded .ui-btn-icon-top .ui-icon{top:15px}.ui-navbar-expanded .ui-btn-icon-bottom .ui-btn-inner{padding:15px 5px 45px;text-align:center}.ui-navbar-expanded .ui-btn-icon-bottom .ui-icon{bottom:15px}.ui-navbar-expanded li .ui-btn .ui-btn-inner{min-height:2.5em}.ui-navbar-expanded .ui-navbar-noicons .ui-btn .ui-btn-inner{padding-top:1.8em;padding-bottom:1.9em}.ui-btn{display:block;text-align:center;cursor:pointer;position:relative;margin:.5em 5px;padding:0}.ui-mini{margin:.25em 5px}.ui-btn-inner{padding:.6em 20px;min-width:.75em;display:block;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;position:relative;zoom:1}.ui-btn input,.ui-btn button{z-index:2}.ui-btn-left,.ui-btn-right,.ui-btn-inline{display:inline-block}.ui-btn-block{display:block}.ui-header .ui-btn,.ui-footer .ui-btn{display:inline-block;margin:0}.ui-header .ui-btn-inner,.ui-footer .ui-btn-inner,.ui-mini .ui-btn-inner{font-size:12.5px;padding:.55em 11px .5em}.ui-header .ui-fullsize .ui-btn-inner,.ui-footer .ui-fullsize .ui-btn-inner{font-size:16px;padding:.6em 25px}.ui-btn-icon-notext{width:24px;height:24px}.ui-btn-icon-notext .ui-btn-inner{padding:0;height:100%}.ui-btn-icon-notext .ui-btn-inner .ui-icon{margin:2px 1px 2px 3px}.ui-btn-text{position:relative;z-index:1;width:100%}.ui-btn-icon-notext .ui-btn-text{position:absolute;left:-9999px}.ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-btn-icon-right .ui-btn-inner{padding-right:40px}.ui-btn-icon-top .ui-btn-inner{padding-top:40px}.ui-btn-icon-bottom .ui-btn-inner{padding-bottom:40px}.ui-header .ui-btn-icon-left .ui-btn-inner,.ui-footer .ui-btn-icon-left .ui-btn-inner,.ui-mini .ui-btn-icon-left .ui-btn-inner{padding-left:30px}.ui-header .ui-btn-icon-right .ui-btn-inner,.ui-footer .ui-btn-icon-right .ui-btn-inner,.ui-mini .ui-btn-icon-right .ui-btn-inner{padding-right:30px}.ui-header .ui-btn-icon-top .ui-btn-inner,.ui-footer .ui-btn-icon-top .ui-btn-inner,.ui-mini .ui-btn-icon-top .ui-btn-inner{padding:30px 3px .5em 3px}.ui-header .ui-btn-icon-bottom .ui-btn-inner,.ui-footer .ui-btn-icon-bottom .ui-btn-inner,.ui-mini .ui-btn-icon-bottom .ui-btn-inner{padding:.55em 3px 30px 3px}.ui-btn-icon-notext .ui-icon{display:block;z-index:0}.ui-btn-icon-left .ui-btn-inner .ui-icon,.ui-btn-icon-right .ui-btn-inner .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-btn-icon-top .ui-btn-inner .ui-icon,.ui-btn-icon-bottom .ui-btn-inner .ui-icon{position:absolute;left:50%;margin-left:-9px}.ui-btn-icon-left .ui-icon{left:10px}.ui-btn-icon-right .ui-icon{right:10px}.ui-btn-icon-top .ui-icon{top:10px}.ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-header .ui-btn-icon-left .ui-icon,.ui-footer .ui-btn-icon-left .ui-icon,.ui-mini.ui-btn-icon-left .ui-icon,.ui-mini .ui-btn-icon-left .ui-icon{left:5px}.ui-header .ui-btn-icon-right .ui-icon,.ui-footer .ui-btn-icon-right .ui-icon,.ui-mini.ui-btn-icon-right .ui-icon,.ui-mini .ui-btn-icon-right .ui-icon{right:5px}.ui-header .ui-btn-icon-top .ui-icon,.ui-footer .ui-btn-icon-top .ui-icon,.ui-mini.ui-btn-icon-top .ui-icon,.ui-mini .ui-btn-icon-top .ui-icon{top:5px}.ui-header .ui-btn-icon-bottom .ui-icon,.ui-footer .ui-btn-icon-bottom .ui-icon,.ui-mini.ui-btn-icon-bottom .ui-icon,.ui-mini .ui-btn-icon-bottom .ui-icon{bottom:5px}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:button;opacity:.1;cursor:pointer;background:#fff;background:rgba(255,255,255,0);filter:Alpha(Opacity=.0001);font-size:1px;border:0;text-indent:-9999px}.ui-collapsible{margin:.5em 0}.ui-collapsible-heading{font-size:16px;display:block;margin:0 -8px;padding:0;border-width:0 0 1px 0;position:relative}.ui-collapsible-heading a{text-align:left;margin:0}.ui-collapsible-heading .ui-btn-inner,.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner{padding-left:12px;padding-right:40px}.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner{padding-right:40px;text-align:center}.ui-collapsible-heading a span.ui-btn{position:absolute;left:6px;top:50%;margin:-12px 0 0 0;width:20px;height:20px;padding:1px 0 1px 2px;text-indent:-9999px}.ui-collapsible-heading a span.ui-btn .ui-btn-inner{padding:10px 0}.ui-collapsible-heading a span.ui-btn .ui-icon{left:0;margin-top:-10px}.ui-collapsible-heading-status{position:absolute;top:-9999px;left:0}.ui-collapsible-content{display:block;margin:0 -8px;padding:10px 16px;border-top:0;background-image:none;font-weight:normal}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set{margin:.5em 0}.ui-collapsible-set .ui-collapsible{margin:-1px 0 0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:0 0 .5em;zoom:1}.ui-bar .ui-controlgroup{margin:0 .3em}.ui-controlgroup-label{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .4em}.ui-controlgroup-controls{display:block;width:100%}.ui-controlgroup li{list-style:none}.ui-controlgroup-vertical .ui-btn,.ui-controlgroup-vertical .ui-checkbox,.ui-controlgroup-vertical .ui-radio{margin:0;border-bottom-width:0}.ui-controlgroup-controls label.ui-select{position:absolute;left:-9999px}.ui-controlgroup-vertical .ui-controlgroup-last{border-bottom-width:1px}.ui-controlgroup-horizontal{padding:0}.ui-controlgroup-horizontal .ui-btn-inner{text-align:center}.ui-controlgroup-horizontal .ui-btn,.ui-controlgroup-horizontal .ui-select{display:inline-block;margin:0 -6px 0 0}.ui-controlgroup-horizontal .ui-checkbox,.ui-controlgroup-horizontal .ui-radio{float:left;clear:none;margin:0 -1px 0 0}.ui-controlgroup-horizontal .ui-checkbox .ui-btn,.ui-controlgroup-horizontal .ui-radio .ui-btn,.ui-controlgroup-horizontal .ui-checkbox:last-child,.ui-controlgroup-horizontal .ui-radio:last-child{margin-right:0}.ui-controlgroup-horizontal .ui-controlgroup-last{margin-right:0}.ui-controlgroup .ui-checkbox label,.ui-controlgroup .ui-radio label{font-size:16px}@media all and (min-width:450px){.ui-field-contain .ui-controlgroup-label{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-controlgroup-controls{width:60%;display:inline-block}.ui-field-contain .ui-controlgroup .ui-select{width:100%}.ui-field-contain .ui-controlgroup-horizontal .ui-select{width:auto}}.ui-dialog{background:none!important}.ui-dialog-contain{width:92.5%;max-width:500px;margin:10% auto 15px auto;padding:0}.ui-dialog .ui-header{margin-top:15%;border:0;overflow:hidden}.ui-dialog .ui-header,.ui-dialog .ui-content,.ui-dialog .ui-footer{display:block;position:relative;width:auto}.ui-dialog .ui-header,.ui-dialog .ui-footer{z-index:10;padding:0}.ui-dialog .ui-footer{padding:0 15px}.ui-dialog .ui-content{padding:15px}.ui-dialog{margin-top:-15px}.ui-checkbox,.ui-radio{position:relative;clear:both;margin:.2em 0 .5em;z-index:1}.ui-checkbox .ui-btn,.ui-radio .ui-btn{margin:0;text-align:left;z-index:2}.ui-checkbox .ui-btn-inner,.ui-radio .ui-btn-inner{white-space:normal}.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner{padding-left:45px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-left .ui-btn-inner{padding-left:36px}.ui-checkbox .ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:36px}.ui-checkbox .ui-btn-icon-top .ui-btn-inner,.ui-radio .ui-btn-icon-top .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-btn-icon-bottom .ui-btn-inner,.ui-radio .ui-btn-icon-bottom .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-icon,.ui-radio .ui-icon{top:1.1em}.ui-checkbox .ui-btn-icon-left .ui-icon,.ui-radio .ui-btn-icon-left .ui-icon{left:15px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon,.ui-radio .ui-mini.ui-btn-icon-left .ui-icon{left:9px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-checkbox .ui-btn-icon-top .ui-icon,.ui-radio .ui-btn-icon-top .ui-icon{top:10px}.ui-checkbox .ui-btn-icon-bottom .ui-icon,.ui-radio .ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-checkbox input,.ui-radio input{position:absolute;left:20px;top:50%;width:10px;height:10px;margin:-5px 0 0 0;outline:0!important;z-index:1}.ui-field-contain,fieldset.ui-field-contain{padding:.8em 0;margin:0;border-width:0 0 1px 0;overflow:visible}.ui-field-contain:first-child{border-top-width:0}.ui-header .ui-field-contain-left,.ui-header .ui-field-contain-right{position:absolute;top:0;width:25%}.ui-header .ui-field-contain-left{left:1em}.ui-header .ui-field-contain-right{right:1em}@media all and (min-width:450px){.ui-field-contain,.ui-mobile fieldset.ui-field-contain{border-width:0;padding:0;margin:1em 0}}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn{overflow:hidden;opacity:1;margin:0}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:button;left:0;top:0;width:100%;min-height:1.5em;min-height:100%;height:3em;max-height:100%;opacity:0;-ms-filter:"alpha(opacity=0)";filter:alpha(opacity=0);z-index:2}.ui-select .ui-disabled{opacity:.3}@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:.0001}}.ui-select .ui-btn select.ui-select-nativeonly{opacity:1;text-indent:0}.ui-select .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-select .ui-btn-icon-right .ui-icon{right:15px}.ui-select .ui-mini.ui-btn-icon-right .ui-icon{right:7px}label.ui-select{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}.ui-select .ui-btn-text,.ui-selectmenu .ui-btn-text{display:block;min-height:1em;overflow:hidden!important}.ui-select .ui-btn-text{text-overflow:ellipsis}.ui-selectmenu{position:absolute;padding:0;z-index:1100!important;width:80%;max-width:350px;padding:6px}.ui-selectmenu .ui-listview{margin:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-selectmenu-hidden{top:-9999px;left:-9999px}.ui-selectmenu-screen{position:absolute;top:0;left:0;width:100%;height:100%;z-index:99}.ui-screen-hidden,.ui-selectmenu-list .ui-li .ui-icon{display:none}.ui-selectmenu-list .ui-li .ui-icon{display:block}.ui-li.ui-selectmenu-placeholder{display:none}.ui-selectmenu .ui-header .ui-title{margin:.6em 46px .8em}@media all and (min-width:450px){.ui-field-contain label.ui-select{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-select{width:60%;display:inline-block}}.ui-selectmenu .ui-header h1:after{content:'.';visibility:hidden}label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}input.ui-input-text,textarea.ui-input-text{background-image:none;padding:.4em;line-height:1.4;font-size:16px;display:block;width:97%;outline:0}.ui-header input.ui-input-text,.ui-footer input.ui-input-text{margin-left:1.25%;padding:.4em 1%;width:95.5%}input.ui-input-text{-webkit-appearance:none}textarea.ui-input-text{height:50px;-webkit-transition:height 200ms linear;-moz-transition:height 200ms linear;-o-transition:height 200ms linear;transition:height 200ms linear}.ui-input-search{padding:0 30px;background-image:none;position:relative}.ui-icon-searchfield:after{position:absolute;left:7px;top:50%;margin-top:-9px;content:"";width:18px;height:18px;opacity:.5}.ui-input-search input.ui-input-text{border:0;width:98%;padding:.4em 0;margin:0;display:block;background:transparent none;outline:0!important}.ui-input-search .ui-input-clear{position:absolute;right:0;top:50%;margin-top:-13px}.ui-mini .ui-input-clear{right:-3px}.ui-input-search .ui-input-clear-hidden{display:none}input.ui-mini,.ui-mini input,textarea.ui-mini{font-size:14px}textarea.ui-mini{height:45px}@media all and (min-width:450px){.ui-field-contain label.ui-input-text{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search{width:60%;display:inline-block}.ui-field-contain .ui-input-search{width:50%}.ui-hide-label input.ui-input-text,.ui-hide-label textarea.ui-input-text,.ui-hide-label .ui-input-search{padding:.4em;width:97%}.ui-input-search input.ui-input-text{width:98%}}.ui-listview{margin:0;counter-reset:listnumbering}.ui-content .ui-listview{margin:-15px}.ui-content .ui-listview-inset{margin:1em 0}.ui-listview,.ui-li{list-style:none;padding:0}.ui-li,.ui-li.ui-field-contain{display:block;margin:0;position:relative;overflow:visible;text-align:left;border-width:0;border-top-width:1px}.ui-li .ui-btn-text a.ui-link-inherit{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-divider,.ui-li-static{padding:.5em 15px;font-size:14px;font-weight:bold}.ui-li-divider{counter-reset:listnumbering}ol.ui-listview .ui-link-inherit:before,ol.ui-listview .ui-li-static:before,.ui-li-dec{font-size:.8em;display:inline-block;padding-right:.3em;font-weight:normal;counter-increment:listnumbering;content:counter(listnumbering) ". "}ol.ui-listview .ui-li-jsnumbering:before{content:""!important}.ui-listview-inset .ui-li{border-right-width:1px;border-left-width:1px}.ui-li:last-child,.ui-li.ui-field-contain:last-child{border-bottom-width:1px}.ui-li>.ui-btn-inner{display:block;position:relative;padding:0}.ui-li .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li{padding:.7em 15px .7em 15px;display:block}.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-thumb{min-height:60px;padding-left:100px}.ui-li-has-icon .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-icon{min-height:20px;padding-left:40px}.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-count{padding-right:45px}.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow{padding-right:30px}.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow.ui-li-has-count{padding-right:75px}.ui-li-has-count .ui-btn-text{padding-right:15px}.ui-li-heading{font-size:16px;font-weight:bold;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-desc{font-size:12px;font-weight:normal;display:block;margin:-.5em 0 .6em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-thumb,.ui-listview .ui-li-icon{position:absolute;left:1px;top:0;max-height:80px;max-width:80px}.ui-listview .ui-li-icon{max-height:40px;max-width:40px;left:10px;top:.9em}.ui-li-thumb,.ui-listview .ui-li-icon,.ui-li-content{float:left;margin-right:10px}.ui-li-aside{float:right;width:50%;text-align:right;margin:.3em 0}@media all and (min-width:480px){.ui-li-aside{width:45%}}.ui-li-divider{cursor:default}.ui-li-has-alt .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt{padding-right:95px}.ui-li-has-count .ui-li-count{position:absolute;font-size:11px;font-weight:bold;padding:.2em .5em;top:50%;margin-top:-.9em;right:48px}.ui-li-divider .ui-li-count,.ui-li-static .ui-li-count{right:10px}.ui-li-has-alt .ui-li-count{right:55px}.ui-li-link-alt{position:absolute;width:40px;height:100%;border-width:0;border-left-width:1px;top:0;right:0;margin:0;padding:0;z-index:2}.ui-li-link-alt .ui-btn{overflow:hidden;position:absolute;right:8px;top:50%;margin:-11px 0 0 0;border-bottom-width:1px;z-index:-1}.ui-li-link-alt .ui-btn-inner{padding:0;height:100%;position:absolute;width:100%;top:0;left:0}.ui-li-link-alt .ui-btn .ui-icon{right:50%;margin-right:-9px}.ui-listview * .ui-btn-inner>.ui-btn>.ui-btn-inner{border-top:0}.ui-listview-filter{border-width:0;overflow:hidden;margin:-15px -15px 15px -15px}.ui-listview-filter .ui-input-search{margin:5px;width:auto;display:block}.ui-listview-filter-inset{margin:-15px -5px -15px -5px;background:transparent}.ui-li.ui-screen-hidden{display:none}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}label.ui-slider{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}input.ui-slider-input,.ui-field-contain input.ui-slider-input{display:inline-block;width:50px}select.ui-slider-switch{display:none}div.ui-slider{position:relative;display:inline-block;overflow:visible;height:15px;padding:0;margin:0 2% 0 20px;top:4px;width:65%}div.ui-slider-mini{height:12px;margin-left:10px}div.ui-slider-bg{border:0;height:100%;padding-right:8px}.ui-controlgroup a.ui-slider-handle,a.ui-slider-handle{position:absolute;z-index:1;top:50%;width:28px;height:28px;margin-top:-15px;margin-left:-15px;outline:0}a.ui-slider-handle .ui-btn-inner{padding:0;height:100%}div.ui-slider-mini a.ui-slider-handle{height:14px;width:14px;margin:-8px 0 0 -7px}div.ui-slider-mini a.ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:-9px 0 0 -9px}@media all and (min-width:450px){.ui-field-contain label.ui-slider{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain div.ui-slider{width:43%}.ui-field-contain div.ui-slider-switch{width:5.5em}}div.ui-slider-switch{height:32px;margin-left:0;width:5.8em}a.ui-slider-handle-snapping{-webkit-transition:left 70ms linear;-moz-transition:left 70ms linear}div.ui-slider-switch .ui-slider-handle{margin-top:1px}.ui-slider-inneroffset{margin:0 16px;position:relative;z-index:1}div.ui-slider-switch.ui-slider-mini{width:5em;height:29px}div.ui-slider-switch.ui-slider-mini .ui-slider-inneroffset{margin:0 15px 0 14px}div.ui-slider-switch.ui-slider-mini .ui-slider-handle{width:25px;height:25px;margin:1px 0 0 -13px}div.ui-slider-switch.ui-slider-mini a.ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:0}span.ui-slider-label{position:absolute;text-align:center;width:100%;overflow:hidden;font-size:16px;top:0;line-height:2;min-height:100%;border-width:0;white-space:nowrap}.ui-slider-mini span.ui-slider-label{font-size:14px}span.ui-slider-label-a{z-index:1;left:0;text-indent:-1.5em}span.ui-slider-label-b{z-index:0;right:0;text-indent:1.5em}.ui-slider-inline{width:120px;display:inline-block}Orthanc-0.7.2/OrthancExplorer/libs/jquery.mobile-1.1.0.min.js0000644000000000000000000026150212237177136021673 0ustar 00000000000000/*! jQuery Mobile v1.1.0 db342b1f315c282692791aa870455901fdb46a55 jquerymobile.com | jquery.org/license */ (function(D,s,k){typeof define==="function"&&define.amd?define(["jquery"],function(a){k(a,D,s);return a.mobile}):k(D.jQuery,D,s)})(this,document,function(D,s,k){(function(a,c,b,e){function f(a){for(;a&&typeof a.originalEvent!=="undefined";)a=a.originalEvent;return a}function d(b){for(var d={},f,g;b;){f=a.data(b,t);for(g in f)if(f[g])d[g]=d.hasVirtualBinding=true;b=b.parentNode}return d}function g(){y&&(clearTimeout(y),y=0);y=setTimeout(function(){F=y=0;C.length=0;z=false;G=true},a.vmouse.resetTimerDuration)} function h(b,d,g){var c,h;if(!(h=g&&g[b])){if(g=!g)a:{for(g=d.target;g;){if((h=a.data(g,t))&&(!b||h[b]))break a;g=g.parentNode}g=null}h=g}if(h){c=d;var g=c.type,z,j;c=a.Event(c);c.type=b;h=c.originalEvent;z=a.event.props;g.search(/^(mouse|click)/)>-1&&(z=w);if(h)for(j=z.length;j;)b=z[--j],c[b]=h[b];if(g.search(/mouse(down|up)|click/)>-1&&!c.which)c.which=1;if(g.search(/^touch/)!==-1&&(b=f(h),g=b.touches,b=b.changedTouches,g=g&&g.length?g[0]:b&&b.length?b[0]:e))for(h=0,len=u.length;hz||Math.abs(c.pageY-E)>z;flags=d(b.target);A&&!e&&h("vmousecancel",b,flags);h("vmousemove",b,flags);g()}}function l(a){if(!G){G=true;var b=d(a.target),c;h("vmouseup",a,b);if(!A&&(c=h("vclick",a,b))&&c.isDefaultPrevented())c=f(a).changedTouches[0],C.push({touchID:F,x:c.clientX,y:c.clientY}),z=true;h("vmouseout",a,b);A=false;g()}}function r(b){var b= a.data(b,t),d;if(b)for(d in b)if(b[d])return true;return false}function n(){}function k(b){var d=b.substr(1);return{setup:function(){r(this)||a.data(this,t,{});a.data(this,t)[b]=true;v[b]=(v[b]||0)+1;v[b]===1&&H.bind(d,j);a(this).bind(d,n);if(K)v.touchstart=(v.touchstart||0)+1,v.touchstart===1&&H.bind("touchstart",o).bind("touchend",l).bind("touchmove",p).bind("scroll",m)},teardown:function(){--v[b];v[b]||H.unbind(d,j);K&&(--v.touchstart,v.touchstart||H.unbind("touchstart",o).unbind("touchmove",p).unbind("touchend", l).unbind("scroll",m));var f=a(this),g=a.data(this,t);g&&(g[b]=false);f.unbind(d,n);r(this)||f.removeData(t)}}}var t="virtualMouseBindings",x="virtualTouchID",c="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),u="clientX clientY pageX pageY screenX screenY".split(" "),w=a.event.props.concat(a.event.mouseHooks?a.event.mouseHooks.props:[]),v={},y=0,s=0,E=0,A=false,C=[],z=false,G=false,K="addEventListener"in b,H=a(b),L=1,F=0;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10, resetTimerDuration:1500};for(var I=0;I7);a.fn[f]=function(a){return a?this.bind(f,a):this.trigger(f)};a.fn[f].delay=50;h[f]=a.extend(h[f],{setup:function(){if(o)return false;a(g.start)},teardown:function(){if(o)return false;a(g.stop)}});g=function(){function g(){var b=e(),d=t(r);if(b!==r)k(r=b,d),a(c).trigger(f);else if(d!==r)location.href=location.href.replace(/#.*/,"")+d;j=setTimeout(g,a.fn[f].delay)}var h={},j,r=e(),n=function(a){return a},k= n,t=n;h.start=function(){j||g()};h.stop=function(){j&&clearTimeout(j);j=b};a.browser.msie&&!o&&function(){var b,c;h.start=function(){if(!b)c=(c=a.fn[f].src)&&c+e(),b=a('