Mercurial > hg > orthanc
diff Resources/WebAssembly/dcdict.h @ 2513:97a74f0eac7a
loading DICOM dictionaries in sandboxed environments
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 28 Mar 2018 18:02:07 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/WebAssembly/dcdict.h Wed Mar 28 18:02:07 2018 +0200 @@ -0,0 +1,302 @@ +/* + * + * Copyright (C) 1994-2015, OFFIS e.V. + * All rights reserved. See COPYRIGHT file for details. + * + * This software and supporting documentation were developed by + * + * OFFIS e.V. + * R&D Division Health + * Escherweg 2 + * D-26121 Oldenburg, Germany + * + * + * Module: dcmdata + * + * Author: Andrew Hewett + * + * Purpose: Interface for loadable DICOM data dictionary + * + */ + + +#ifndef DCMDICT_H +#define DCMDICT_H + +#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ + +#include "dcmtk/ofstd/ofthread.h" +#include "dcmtk/dcmdata/dchashdi.h" + +/// maximum length of a line in the loadable DICOM dictionary +#define DCM_MAXDICTLINESIZE 2048 + +/// maximum number of fields per entry in the loadable DICOM dictionary +#define DCM_MAXDICTFIELDS 6 + +/// environment variable pointing to the data dictionary file +#define DCM_DICT_ENVIRONMENT_VARIABLE "DCMDICTPATH" + +#ifndef DCM_DICT_DEFAULT_PATH +/* +** The default dictionary path is system dependent. It should +** be defined in a configuration file included from "osconfig.h" +*/ +#error "DCM_DICT_DEFAULT_PATH is not defined via osconfig.h" +#endif /* !DCM_DICT_DEFAULT_PATH */ + +#ifndef ENVIRONMENT_PATH_SEPARATOR +#define ENVIRONMENT_PATH_SEPARATOR '\n' /* at least define something unlikely */ +#endif + + +/** this class implements a loadable DICOM Data Dictionary + */ +class DCMTK_DCMDATA_EXPORT DcmDataDictionary +{ +public: + + /** constructor + * @param loadBuiltin flag indicating if a built-in data dictionary + * (if any) should be loaded. + * @param loadExternal flag indicating if an external data dictionary + * should be read from file. + */ + DcmDataDictionary(OFBool loadBuiltin, OFBool loadExternal); + + /// destructor + ~DcmDataDictionary(); + + /** checks if a data dictionary is loaded (excluding the skeleton dictionary) + * @return true if loaded, false if no dictionary is present + */ + OFBool isDictionaryLoaded() const { return dictionaryLoaded; } + + /// returns the number of normal (non-repeating) tag entries + int numberOfNormalTagEntries() const { return hashDict.size(); } + + /// returns the number of repeating tag entries + int numberOfRepeatingTagEntries() const { return OFstatic_cast(int, repDict.size()); } + + /** returns the number of dictionary entries that were loaded + * either from file or from a built-in dictionary or both. + */ + int numberOfEntries() const + { return numberOfNormalTagEntries() + + numberOfRepeatingTagEntries() - skeletonCount; } + + /** returns the number of skeleton entries. The skeleton is a collection + * of dictionary entries which are always present, even if neither internal + * nor external dictionary have been loaded. It contains very basic + * things like item delimitation and sequence delimitation. + */ + int numberOfSkeletonEntries() const { return skeletonCount; } + + /** reload data dictionaries. First, all dictionary entries are deleted. + * @param loadBuiltin flag indicating if a built-in data dictionary + * (if any) should be loaded. + * @param loadExternal flag indicating if an external data dictionary + * should be read from file. + * @return true if reload was successful, false if an error occurred + */ + OFBool reloadDictionaries(OFBool loadBuiltin, OFBool loadExternal); + + /** load a particular dictionary from file. + * @param fileName filename + * @param errorIfAbsent causes the method to return false + * if the file cannot be opened + * @return false if the file contains a parse error or if the file could + * not be opened and errorIfAbsent was set, true otherwise. + */ + OFBool loadDictionary(const char* fileName, OFBool errorIfAbsent = OFTrue); + + /** dictionary lookup for the given tag key and private creator name. + * First the normal tag dictionary is searched. If not found + * then the repeating tag dictionary is searched. + * @param key tag key + * @param privCreator private creator name, may be NULL + */ + const DcmDictEntry* findEntry(const DcmTagKey& key, const char *privCreator) const; + + /** dictionary lookup for the given attribute name. + * First the normal tag dictionary is searched. If not found + * then the repeating tag dictionary is searched. + * Only considers standard attributes (i. e. without private creator) + * @param name attribute name + */ + const DcmDictEntry* findEntry(const char *name) const; + + /// deletes all dictionary entries + void clear(); + + /** adds an entry to the dictionary. Must be allocated via new. + * The entry becomes the property of the dictionary and will be + * deallocated (via delete) upon clear() or dictionary destruction. + * If an equivalent entry already exists it will be replaced by + * the new entry and the old entry deallocated (via delete). + * @param entry pointer to new entry + */ + void addEntry(DcmDictEntry* entry); + + /* Iterators to access the normal and the repeating entries */ + + /// returns an iterator to the start of the normal (non-repeating) dictionary + DcmHashDictIterator normalBegin() { return hashDict.begin(); } + + /// returns an iterator to the end of the normal (non-repeating) dictionary + DcmHashDictIterator normalEnd() { return hashDict.end(); } + + /// returns an iterator to the start of the repeating tag dictionary + DcmDictEntryListIterator repeatingBegin() { return repDict.begin(); } + + /// returns an iterator to the end of the repeating tag dictionary + DcmDictEntryListIterator repeatingEnd() { return repDict.end(); } + + // Function by the Orthanc project to load a dictionary from a + // memory buffer, which is necessary in sandboxed + // environments. This is an adapted version of + // DcmDataDictionary::loadDictionary(). + OFBool loadFromMemory(const std::string& content, OFBool errorIfAbsent = OFTrue); + +private: + + /** private undefined assignment operator + */ + DcmDataDictionary &operator=(const DcmDataDictionary &); + + /** private undefined copy constructor + */ + DcmDataDictionary(const DcmDataDictionary &); + + /** loads external dictionaries defined via environment variables + * @return true if successful + */ + OFBool loadExternalDictionaries(); + + /** loads a builtin (compiled) data dictionary. + * Depending on which code is in use, this function may not + * do anything. + */ + void loadBuiltinDictionary(); + + /** loads the skeleton dictionary (the bare minimum needed to run) + * @return true if successful + */ + OFBool loadSkeletonDictionary(); + + /** looks up the given directory entry in the two dictionaries. + * @return pointer to entry if found, NULL otherwise + */ + const DcmDictEntry* findEntry(const DcmDictEntry& entry) const; + + /** deletes the given entry from either dictionary + */ + void deleteEntry(const DcmDictEntry& entry); + + + /** dictionary of normal tags + */ + DcmHashDict hashDict; + + /** dictionary of repeating tags + */ + DcmDictEntryList repDict; + + /** the number of skeleton entries + */ + int skeletonCount; + + /** is a dictionary loaded (more than skeleton) + */ + OFBool dictionaryLoaded; + +}; + + +/** global singleton dicom dictionary that is used by DCMTK in order to lookup + * attribute VR, tag names and so on. The dictionary is internally populated + * on first use, if the user accesses it via rdlock() or wrlock(). The + * dictionary allows safe read (shared) and write (exclusive) access from + * multiple threads in parallel. + */ +class DCMTK_DCMDATA_EXPORT GlobalDcmDataDictionary +{ +public: + /** constructor. + */ + GlobalDcmDataDictionary(); + + /** destructor + */ + ~GlobalDcmDataDictionary(); + + /** acquires a read lock and returns a const reference to + * the dictionary. + * @return const reference to dictionary + */ + const DcmDataDictionary& rdlock(); + + /** acquires a write lock and returns a non-const reference + * to the dictionary. + * @return non-const reference to dictionary. + */ + DcmDataDictionary& wrlock(); + + /** unlocks the read or write lock which must have been acquired previously. + */ + void unlock(); + + /** checks if a data dictionary has been loaded. This method acquires and + * releases a read lock. It must not be called with another lock on the + * dictionary being held by the calling thread. + * @return OFTrue if dictionary has been loaded, OFFalse otherwise. + */ + OFBool isDictionaryLoaded(); + + /** erases the contents of the dictionary. This method acquires and + * releases a write lock. It must not be called with another lock on the + * dictionary being held by the calling thread. This method is intended + * as a help for debugging memory leaks. + */ + void clear(); + +private: + /** private undefined assignment operator + */ + GlobalDcmDataDictionary &operator=(const GlobalDcmDataDictionary &); + + /** private undefined copy constructor + */ + GlobalDcmDataDictionary(const GlobalDcmDataDictionary &); + + /** create the data dictionary instance for this class. Used for first + * intialization. The caller must not have dataDictLock locked. + */ + void createDataDict(); + + /** the data dictionary managed by this class + */ + DcmDataDictionary *dataDict; + +#ifdef WITH_THREADS + /** the read/write lock used to protect access from multiple threads + */ + OFReadWriteLock dataDictLock; +#endif +}; + + +/** The Global DICOM Data Dictionary. + * Will be created before main() starts and gets populated on its first use. + * Tries to load a builtin data dictionary (if compiled in). + * Tries to load data dictionaries from files specified by + * the DCMDICTPATH environment variable. If this environment + * variable does not exist then a default file is loaded (if + * it exists). + * It is possible that no data dictionary gets loaded. This + * is likely to cause unexpected behaviour in the dcmdata + * toolkit classes. + */ +extern DCMTK_DCMDATA_EXPORT GlobalDcmDataDictionary dcmDataDict; + +#endif