diff --git a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp index 85ac657069..3b76d4aa9e 100644 --- a/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp +++ b/Core/Code/CppMicroServices/src/module/usModuleResourceBuffer.cpp @@ -1,275 +1,275 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "usModuleResourceBuffer_p.h" #include "stdint_p.h" #include #include #ifdef US_PLATFORM_WINDOWS #define DATA_NEEDS_NEWLINE_CONVERSION 1 #undef REMOVE_LAST_NEWLINE_IN_TEXT_MODE #else #undef DATA_NEEDS_NEWLINE_CONVERSION #define REMOVE_LAST_NEWLINE_IN_TEXT_MODE 1 #endif US_BEGIN_NAMESPACE static const std::size_t BUFFER_SIZE = 1024; class ModuleResourceBufferPrivate { public: ModuleResourceBufferPrivate(const char* begin, std::size_t size, std::ios_base::openmode mode) : begin(begin) , end(begin + size) , current(begin) , mode(mode) #ifdef DATA_NEEDS_NEWLINE_CONVERSION , pos(0) #endif { } const char* const begin; const char* const end; const char* current; const std::ios_base::openmode mode; #ifdef DATA_NEEDS_NEWLINE_CONVERSION // records the stream position ignoring CR characters std::streambuf::pos_type pos; #endif }; ModuleResourceBuffer::ModuleResourceBuffer(const unsigned char* data, std::size_t _size, std::ios_base::openmode mode) : d(NULL) { assert(_size < static_cast(std::numeric_limits::max())); // assert(data != NULL); const char* begin = reinterpret_cast(data); std::size_t size = _size; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (data != NULL && !(mode & std::ios_base::binary) && begin[0] == '\r') { ++begin; --size; } #endif #ifdef REMOVE_LAST_NEWLINE_IN_TEXT_MODE if(data != NULL && !(mode & std::ios_base::binary) && begin[size-1] == '\n') { --size; } #endif d = new ModuleResourceBufferPrivate(begin, size, mode); } ModuleResourceBuffer::~ModuleResourceBuffer() { delete d; } ModuleResourceBuffer::int_type ModuleResourceBuffer::underflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current + 1 == d->end) { return traits_type::eof(); } c = d->current[1]; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::uflow() { if (d->current == d->end) return traits_type::eof(); #ifdef DATA_NEEDS_NEWLINE_CONVERSION char c = *d->current++; if (!(d->mode & std::ios_base::binary)) { if (c == '\r') { if (d->current == d->end) { return traits_type::eof(); } c = *d->current++; } } return traits_type::to_int_type(c); #else return traits_type::to_int_type(*d->current++); #endif } ModuleResourceBuffer::int_type ModuleResourceBuffer::pbackfail(int_type ch) { int backOffset = -1; #ifdef DATA_NEEDS_NEWLINE_CONVERSION if (!(d->mode & std::ios_base::binary)) { while ((d->current - backOffset) >= d->begin && d->current[backOffset] == '\r') { --backOffset; } // d->begin always points to a character != '\r' } #endif if (d->current == d->begin || (ch != traits_type::eof() && ch != d->current[backOffset])) { return traits_type::eof(); } d->current += backOffset; return traits_type::to_int_type(*d->current); } std::streamsize ModuleResourceBuffer::showmanyc() { - assert(std::less_equal()(d->current, d->end)); + assert(d->current <= d->end); #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streamsize ssize = 0; std::size_t chunkSize = d->end - d->current; for (std::size_t i = 0; i < chunkSize; ++i) { if (d->current[i] != '\r') { ++ssize; } } return ssize; #else return d->end - d->current; #endif } std::streambuf::pos_type ModuleResourceBuffer::seekoff(std::streambuf::off_type off, std::ios_base::seekdir way, std::ios_base::openmode /*which*/) { #ifdef DATA_NEEDS_NEWLINE_CONVERSION std::streambuf::off_type step = 1; if (way == std::ios_base::beg) { d->current = d->begin; } else if (way == std::ios_base::end) { d->current = d->end; step = -1; } if (!(d->mode & std::ios_base::binary)) { if (way == std::ios_base::beg) { d->pos = 0; } else if (way == std::ios_base::end) { d->current -= 1; } std::streambuf::off_type i = 0; // scan through off amount of characters excluding '\r' while (i != off) { if (*d->current != '\r') { i += step; d->pos += step; } d->current += step; } // adjust the position in case of a "backwards" seek if (way == std::ios_base::end) { // fix pointer from previous while loop d->current += 1; d->pos = 0; i = 0; const std::streampos currInternalPos = d->current - d->begin; while (i != currInternalPos) { if (d->begin[i] != '\r') { d->pos += 1; } ++i; } } } else { d->current += off; d->pos = d->current - d->begin; } return d->pos; #else if (way == std::ios_base::beg) { d->current = d->begin + off; return off; } else if (way == std::ios_base::cur) { d->current += off; return d->current - d->begin; } else { d->current = d->end + off; return d->current - d->begin; } #endif } std::streambuf::pos_type ModuleResourceBuffer::seekpos(std::streambuf::pos_type sp, std::ios_base::openmode /*which*/) { return this->seekoff(sp, std::ios_base::beg); } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/src/service/usServiceTracker.tpp b/Core/Code/CppMicroServices/src/service/usServiceTracker.tpp index 742291b621..17388d634f 100644 --- a/Core/Code/CppMicroServices/src/service/usServiceTracker.tpp +++ b/Core/Code/CppMicroServices/src/service/usServiceTracker.tpp @@ -1,448 +1,448 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usServiceTrackerPrivate.h" #include "usTrackedService_p.h" #include "usServiceException.h" #include "usModuleContext.h" #include #include US_BEGIN_NAMESPACE template ServiceTracker::~ServiceTracker() { Close(); delete d; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4355) #endif template ServiceTracker::ServiceTracker(ModuleContext* context, const ServiceReference& reference, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, reference, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const std::string& clazz, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, clazz, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext* context, const LDAPFilter& filter, _ServiceTrackerCustomizer* customizer) : d(new _ServiceTrackerPrivate(this, context, filter, customizer)) { } template ServiceTracker::ServiceTracker(ModuleContext *context, ServiceTrackerCustomizer *customizer) : d(new _ServiceTrackerPrivate(this, context, us_service_interface_iid(), customizer)) { const char* clazz = us_service_interface_iid(); if (clazz == 0) throw ServiceException("The service interface class has no US_DECLARE_SERVICE_INTERFACE macro"); } #ifdef _MSC_VER #pragma warning(pop) #endif template void ServiceTracker::Open() { _TrackedService* t; { typename _ServiceTrackerPrivate::Lock l(d); if (d->trackedService) { return; } US_DEBUG(d->DEBUG) << "ServiceTracker::Open: " << d->filter; t = new _TrackedService(this, d->customizer); { typename _TrackedService::Lock l(*t); try { d->context->AddServiceListener(t, &_TrackedService::ServiceChanged, d->listenerFilter); std::list references; if (!d->trackClass.empty()) { references = d->GetInitialReferences(d->trackClass, std::string()); } else { if (d->trackReference.GetModule() != 0) { references.push_back(d->trackReference); } else { /* user supplied filter */ references = d->GetInitialReferences(std::string(), (d->listenerFilter.empty()) ? d->filter.ToString() : d->listenerFilter); } } /* set tracked with the initial references */ t->SetInitial(references); } catch (const std::invalid_argument& e) { throw std::runtime_error(std::string("unexpected std::invalid_argument exception: ") + e.what()); } } d->trackedService = t; } /* Call tracked outside of synchronized region */ t->TrackInitial(); /* process the initial references */ } template void ServiceTracker::Close() { _TrackedService* outgoing; std::list references; { typename _ServiceTrackerPrivate::Lock l(d); outgoing = d->trackedService; if (outgoing == 0) { return; } US_DEBUG(d->DEBUG) << "ServiceTracker::close:" << d->filter; outgoing->Close(); GetServiceReferences(references); d->trackedService = 0; try { d->context->RemoveServiceListener(outgoing, &_TrackedService::ServiceChanged); } catch (const std::logic_error& /*e*/) { /* In case the context was stopped. */ } } d->Modified(); /* clear the cache */ { typename _TrackedService::Lock l(outgoing); outgoing->NotifyAll(); /* wake up any waiters */ } for(std::list::const_iterator ref = references.begin(); ref != references.end(); ++ref) { outgoing->Untrack(*ref, ServiceEvent()); } if (d->DEBUG) { typename _ServiceTrackerPrivate::Lock l(d); if ((d->cachedReference.GetModule() == 0) && (d->cachedService == 0)) { US_DEBUG(true) << "ServiceTracker::close[cached cleared]:" << d->filter; } } delete outgoing; d->trackedService = 0; } template T ServiceTracker::WaitForService(unsigned long timeoutMillis) { T object = GetService(); while (object == 0) { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return 0; } { typename _TrackedService::Lock l(t); if (t->Size() == 0) { t->Wait(timeoutMillis); } } object = GetService(); } return object; } template void ServiceTracker::GetServiceReferences(std::list& refs) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } { typename _TrackedService::Lock l(t); d->GetServiceReferences_unlocked(refs, t); } } template ServiceReference ServiceTracker::GetServiceReference() const { ServiceReference reference(0); { typename _ServiceTrackerPrivate::Lock l(d); reference = d->cachedReference; } if (reference.GetModule() != 0) { US_DEBUG(d->DEBUG) << "ServiceTracker::getServiceReference[cached]:" << d->filter; return reference; } US_DEBUG(d->DEBUG) << "ServiceTracker::getServiceReference:" << d->filter; std::list references; GetServiceReferences(references); - int length = references.size(); + std::size_t length = references.size(); if (length == 0) { /* if no service is being tracked */ throw ServiceException("No service is being tracked"); } std::list::const_iterator selectedRef; if (length > 1) { /* if more than one service, select highest ranking */ std::vector rankings(length); int count = 0; int maxRanking = std::numeric_limits::min(); std::list::const_iterator refIter = references.begin(); for (int i = 0; i < length; i++) { Any rankingAny = refIter->GetProperty(ServiceConstants::SERVICE_RANKING()); int ranking = 0; if (rankingAny.Type() == typeid(int)) { ranking = any_cast(rankingAny); } rankings[i] = ranking; if (ranking > maxRanking) { selectedRef = refIter; maxRanking = ranking; count = 1; } else { if (ranking == maxRanking) { count++; } } ++refIter; } if (count > 1) { /* if still more than one service, select lowest id */ long int minId = std::numeric_limits::max(); refIter = references.begin(); for (int i = 0; i < length; i++) { if (rankings[i] == maxRanking) { Any idAny = refIter->GetProperty(ServiceConstants::SERVICE_ID()); long int id = 0; if (idAny.Type() == typeid(long int)) { id = any_cast(idAny); } if (id < minId) { selectedRef = refIter; minId = id; } } ++refIter; } } } { typename _ServiceTrackerPrivate::Lock l(d); d->cachedReference = *selectedRef; return d->cachedReference; } } template T ServiceTracker::GetService(const ServiceReference& reference) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return 0; } { typename _TrackedService::Lock l(t); return t->GetCustomizedObject(reference); } } template void ServiceTracker::GetServices(std::list& services) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } { typename _TrackedService::Lock l(t); std::list references; d->GetServiceReferences_unlocked(references, t); for(std::list::const_iterator ref = references.begin(); ref != references.end(); ++ref) { services.push_back(t->GetCustomizedObject(*ref)); } } } template T ServiceTracker::GetService() const { T service = d->cachedService; if (service != 0) { US_DEBUG(d->DEBUG) << "ServiceTracker::getService[cached]:" << d->filter; return service; } US_DEBUG(d->DEBUG) << "ServiceTracker::getService:" << d->filter; try { ServiceReference reference = GetServiceReference(); if (reference.GetModule() == 0) { return 0; } return d->cachedService = GetService(reference); } catch (const ServiceException&) { return 0; } } template void ServiceTracker::Remove(const ServiceReference& reference) { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } t->Untrack(reference, ServiceEvent()); } template int ServiceTracker::Size() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return 0; } { typename _TrackedService::Lock l(t); - return t->Size(); + return static_cast(t->Size()); } } template int ServiceTracker::GetTrackingCount() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return -1; } { typename _TrackedService::Lock l(t); return t->GetTrackingCount(); } } template void ServiceTracker::GetTracked(TrackingMap& map) const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return; } { typename _TrackedService::Lock l(t); t->CopyEntries(map); } } template bool ServiceTracker::IsEmpty() const { _TrackedService* t = d->Tracked(); if (t == 0) { /* if ServiceTracker is not open */ return true; } { typename _TrackedService::Lock l(t); return t->IsEmpty(); } } template T ServiceTracker::AddingService(const ServiceReference& reference) { return dynamic_cast(d->context->GetService(reference)); } template void ServiceTracker::ModifiedService(const ServiceReference& /*reference*/, T /*service*/) { /* do nothing */ } template void ServiceTracker::RemovedService(const ServiceReference& reference, T /*service*/) { d->context->UngetService(reference); } US_END_NAMESPACE diff --git a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp index 8befc18601..b37ccd8dc2 100644 --- a/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp +++ b/Core/Code/CppMicroServices/test/usModuleResourceTest.cpp @@ -1,477 +1,477 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include #include #include #include #include #include #include #include "usTestUtilSharedLibrary.h" #include "usTestingMacros.h" #include #include US_USE_NAMESPACE namespace { void checkResourceInfo(const ModuleResource& res, const std::string& path, const std::string& baseName, const std::string& completeBaseName, const std::string& suffix, const std::string& completeSuffix, int size, bool children = false) { US_TEST_CONDITION_REQUIRED(res.IsValid(), "Valid resource") US_TEST_CONDITION(res.GetBaseName() == baseName, "GetBaseName()") US_TEST_CONDITION(res.GetChildren().empty() == !children, "No children") US_TEST_CONDITION(res.GetCompleteBaseName() == completeBaseName, "GetCompleteBaseName()") US_TEST_CONDITION(res.GetName() == completeBaseName + "." + suffix, "GetName()") US_TEST_CONDITION(res.GetResourcePath() == path + completeBaseName + "." + suffix, "GetResourcePath()") US_TEST_CONDITION(res.GetPath() == path, "GetPath()") US_TEST_CONDITION(res.GetSize() == size, "Data size") US_TEST_CONDITION(res.GetSuffix() == suffix, "Suffix") US_TEST_CONDITION(res.GetCompleteSuffix() == completeSuffix, "Complete suffix") } void testTextResource(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(12); const std::string fileData = "foo and\nbar\n"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } - content.append(buffer, rs.gcount()); + content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); rs.clear(); rs.seekg(0); US_TEST_CONDITION_REQUIRED(rs.tellg() == std::streampos(0), "Move to start") US_TEST_CONDITION_REQUIRED(rs.good(), "Start re-reading"); std::vector lines; std::string line; while (std::getline(rs, line)) { lines.push_back(line); } US_TEST_CONDITION_REQUIRED(lines.size() > 1, "Number of lines") US_TEST_CONDITION(lines[0] == "foo and", "Check first line") US_TEST_CONDITION(lines[1] == "bar", "Check second line") } void testTextResourceAsBinary(Module* module) { ModuleResource res = module->GetResource("foo.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 16, false); const std::streampos ssize(16); const std::string fileData = "foo and\r\nbar\r\n\r\n"; #else checkResourceInfo(res, "/", "foo", "foo", "txt", "txt", 13, false); const std::streampos ssize(13); const std::string fileData = "foo and\nbar\n\n"; #endif ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } - content.append(buffer, rs.gcount()); + content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testInvalidResource(Module* module) { ModuleResource res = module->GetResource("invalid"); US_TEST_CONDITION_REQUIRED(res.IsValid() == false, "Check invalid resource") US_TEST_CONDITION(res.GetName().empty(), "Check empty name") US_TEST_CONDITION(res.GetPath().empty(), "Check empty path") US_TEST_CONDITION(res.GetResourcePath().empty(), "Check empty resource path") US_TEST_CONDITION(res.GetBaseName().empty(), "Check empty base name") US_TEST_CONDITION(res.GetCompleteBaseName().empty(), "Check empty complete base name") US_TEST_CONDITION(res.GetSuffix().empty(), "Check empty suffix") US_TEST_CONDITION(res.GetChildren().empty(), "Check empty children") US_TEST_CONDITION(res.GetSize() == 0, "Check zero size") US_TEST_CONDITION(res.GetData() == NULL, "Check NULL data") ModuleResourceStream rs(res); US_TEST_CONDITION(rs.good() == true, "Check invalid resource stream") rs.ignore(); US_TEST_CONDITION(rs.good() == false, "Check invalid resource stream") US_TEST_CONDITION(rs.eof() == true, "Check invalid resource stream") } void testSpecialCharacters(Module* module) { ModuleResource res = module->GetResource("special_chars.dummy.txt"); #ifdef US_PLATFORM_WINDOWS checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 56, false); const std::streampos ssize(54); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)\n"; #else checkResourceInfo(res, "/", "special_chars", "special_chars.dummy", "txt", "dummy.txt", 54, false); const std::streampos ssize(53); const std::string fileData = "German Füße (feet)\nFrench garçon de café (waiter)"; #endif ModuleResourceStream rs(res); rs.seekg(0, std::ios_base::end); US_TEST_CONDITION(rs.tellg() == ssize, "Stream content length"); rs.seekg(0, std::ios_base::beg); std::string content; content.reserve(res.GetSize()); char buffer[1024]; while (rs.read(buffer, sizeof(buffer))) { content.append(buffer, sizeof(buffer)); } - content.append(buffer, rs.gcount()); + content.append(buffer, static_cast(rs.gcount())); US_TEST_CONDITION(rs.eof(), "EOF check"); US_TEST_CONDITION(content == fileData, "Resource content"); } void testBinaryResource(Module* module) { ModuleResource res = module->GetResource("/icons/cppmicroservices.png"); checkResourceInfo(res, "/icons/", "cppmicroservices", "cppmicroservices", "png", "png", 2424, false); ModuleResourceStream rs(res, std::ios_base::binary); rs.seekg(0, std::ios_base::end); std::streampos resLength = rs.tellg(); rs.seekg(0); std::ifstream png(CppMicroServices_SOURCE_DIR "/test/modules/libRWithResources/resources/icons/cppmicroservices.png", std::ifstream::in | std::ifstream::binary); US_TEST_CONDITION_REQUIRED(png.is_open(), "Open reference file") png.seekg(0, std::ios_base::end); std::streampos pngLength = png.tellg(); png.seekg(0); US_TEST_CONDITION(resLength = res.GetSize(), "Check resource size") US_TEST_CONDITION_REQUIRED(resLength == pngLength, "Compare sizes") char c1 = 0; char c2 = 0; bool isEqual = true; int count = 0; while (png.get(c1) && rs.get(c2)) { ++count; if (c1 != c2) { isEqual = false; break; } } US_TEST_CONDITION_REQUIRED(count == pngLength, "Check if everything was read"); US_TEST_CONDITION_REQUIRED(isEqual, "Equal binary contents"); US_TEST_CONDITION(png.eof(), "EOF check"); } struct ResourceComparator { bool operator()(const ModuleResource& mr1, const ModuleResource& mr2) const { return mr1 < mr2; } }; void testResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 4, "Check child count") US_TEST_CONDITION(children[0] == "foo.txt", "Check child name") US_TEST_CONDITION(children[1] == "icons", "Check child name") US_TEST_CONDITION(children[2] == "special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(children[3] == "test.xml", "Check child name") ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") ModuleResource icons = module->GetResource("icons"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); US_TEST_CONDITION_REQUIRED(children.size() == 2, "Check icons child count") std::sort(children.begin(), children.end()); US_TEST_CONDITION(children[0] == "cppmicroservices.png", "Check child name") US_TEST_CONDITION(children[1] == "readme.txt", "Check child name") ResourceComparator resourceComparator; // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 2, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 3, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") // find all resources nodes = module->FindResources("", "", true); US_TEST_CONDITION(nodes.size() == 5, "Total resource number") nodes = module->FindResources("", "**", true); US_TEST_CONDITION(nodes.size() == 5, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 3, "Check recursive pattern matches") } void testStaticResourceTree(Module* module) { ModuleResource res = module->GetResource(""); US_TEST_CONDITION(res.GetResourcePath() == "/", "Check root file path") US_TEST_CONDITION(res.IsDir() == true, "Check type") std::vector children = res.GetChildren(); std::sort(children.begin(), children.end()); US_TEST_CONDITION_REQUIRED(children.size() == 8, "Check child count") US_TEST_CONDITION(children[0] == "dynamic.txt", "Check dynamic.txt child name") US_TEST_CONDITION(children[1] == "foo.txt", "Check foo.txt child name") US_TEST_CONDITION(children[2] == "icons", "Check icons child name") US_TEST_CONDITION(children[3] == "res.txt", "Check res.txt child name") US_TEST_CONDITION(children[4] == "res.txt", "Check res.txt child name") US_TEST_CONDITION(children[5] == "special_chars.dummy.txt", "Check special_chars.dummy.txt child name") US_TEST_CONDITION(children[6] == "static.txt", "Check static.txt child name") US_TEST_CONDITION(children[7] == "test.xml", "Check test.xml child name") ModuleResource readme = module->GetResource("/icons/readme.txt"); US_TEST_CONDITION(readme.IsFile() && readme.GetChildren().empty(), "Check file resource") ModuleResource icons = module->GetResource("icons"); US_TEST_CONDITION(icons.IsDir() && !icons.IsFile() && !icons.GetChildren().empty(), "Check directory resource") children = icons.GetChildren(); US_TEST_CONDITION_REQUIRED(children.size() == 2, "Check icons child count") std::sort(children.begin(), children.end()); US_TEST_CONDITION(children[0] == "cppmicroservices.png", "Check child name") US_TEST_CONDITION(children[1] == "readme.txt", "Check child name") ResourceComparator resourceComparator; // find all .txt files std::vector nodes = module->FindResources("", "*.txt", false); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 6, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/dynamic.txt", "Check dynamic.txt child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[3].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[4].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(nodes[5].GetResourcePath() == "/static.txt", "Check static.txt child name") nodes = module->FindResources("", "*.txt", true); std::sort(nodes.begin(), nodes.end(), resourceComparator); US_TEST_CONDITION_REQUIRED(nodes.size() == 7, "Found child count") US_TEST_CONDITION(nodes[0].GetResourcePath() == "/dynamic.txt", "Check dynamic.txt child name") US_TEST_CONDITION(nodes[1].GetResourcePath() == "/foo.txt", "Check child name") US_TEST_CONDITION(nodes[2].GetResourcePath() == "/icons/readme.txt", "Check child name") US_TEST_CONDITION(nodes[3].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[4].GetResourcePath() == "/res.txt", "Check res.txt child name") US_TEST_CONDITION(nodes[5].GetResourcePath() == "/special_chars.dummy.txt", "Check child name") US_TEST_CONDITION(nodes[6].GetResourcePath() == "/static.txt", "Check static.txt child name") // find all resources nodes = module->FindResources("", "", true); US_TEST_CONDITION(nodes.size() == 9, "Total resource number") nodes = module->FindResources("", "**", true); US_TEST_CONDITION(nodes.size() == 9, "Total resource number") // test pattern matching nodes.clear(); nodes = module->FindResources("/icons", "*micro*.png", false); US_TEST_CONDITION(nodes.size() == 1 && nodes[0].GetResourcePath() == "/icons/cppmicroservices.png", "Check file pattern matches") nodes.clear(); nodes = module->FindResources("", "*.txt", true); US_TEST_CONDITION(nodes.size() == 7, "Check recursive pattern matches") } void testResourceOperators(Module* module) { ModuleResource invalid = module->GetResource("invalid"); ModuleResource foo = module->GetResource("foo.txt"); US_TEST_CONDITION_REQUIRED(foo.IsValid() && foo, "Check valid resource") ModuleResource foo2(foo); US_TEST_CONDITION(foo == foo, "Check equality operator") US_TEST_CONDITION(foo == foo2, "Check copy constructor and equality operator") US_TEST_CONDITION(foo != invalid, "Check inequality with invalid resource") ModuleResource xml = module->GetResource("/test.xml"); US_TEST_CONDITION_REQUIRED(xml.IsValid() && xml, "Check valid resource") US_TEST_CONDITION(foo != xml, "Check inequality") US_TEST_CONDITION(foo < xml, "Check operator<") // check operator< by using a set std::set resources; resources.insert(foo); resources.insert(foo); resources.insert(xml); US_TEST_CONDITION(resources.size() == 2, "Check operator< with set") // check hash function specialization US_UNORDERED_SET_TYPE resources2; resources2.insert(foo); resources2.insert(foo); resources2.insert(xml); US_TEST_CONDITION(resources2.size() == 2, "Check operator< with unordered set") // check operator<< std::ostringstream oss; oss << foo; US_TEST_CONDITION(oss.str() == foo.GetResourcePath(), "Check operator<<") } void testResourceFromExecutable(Module* module) { ModuleResource resource = module->GetResource("usTestResource.txt"); US_TEST_CONDITION_REQUIRED(resource.IsValid(), "Check valid executable resource") std::string line; ModuleResourceStream rs(resource); std::getline(rs, line); US_TEST_CONDITION(line == "meant to be compiled into the test driver", "Check executable resource content") } } // end unnamed namespace int usModuleResourceTest(int /*argc*/, char* /*argv*/[]) { US_TEST_BEGIN("ModuleResourceTest"); ModuleContext* mc = GetModuleContext(); assert(mc); #ifdef US_BUILD_SHARED_LIBS SharedLibraryHandle libR("TestModuleR"); try { libR.Load(); } catch (const std::exception& e) { US_TEST_FAILED_MSG(<< "Load module exception: " << e.what()) } Module* moduleR = ModuleRegistry::GetModule("TestModuleR Module"); US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module TestModuleR") US_TEST_CONDITION(moduleR->GetName() == "TestModuleR Module", "Test module name") testInvalidResource(moduleR); testResourceTree(moduleR); testResourceFromExecutable(mc->GetModule()); #else Module* moduleR = mc->GetModule(); US_TEST_CONDITION_REQUIRED(moduleR != NULL, "Test for existing module 0") US_TEST_CONDITION(moduleR->GetName() == "CppMicroServices", "Test module name") testStaticResourceTree(moduleR); #endif testResourceOperators(moduleR); testTextResource(moduleR); testTextResourceAsBinary(moduleR); testSpecialCharacters(moduleR); testBinaryResource(moduleR); #ifdef US_BUILD_SHARED_LIBS ModuleResource foo = moduleR->GetResource("foo.txt"); US_TEST_CONDITION(foo.IsValid() == true, "Valid resource") libR.Unload(); US_TEST_CONDITION(foo.IsValid() == false, "Invalidated resource") US_TEST_CONDITION(foo.GetData() == NULL, "NULL data") #endif US_TEST_END() } diff --git a/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp b/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp index c75590e7cc..391a7adb86 100644 --- a/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp +++ b/Core/Code/CppMicroServices/tools/usResourceCompiler.cpp @@ -1,668 +1,668 @@ /*============================================================================= Library: CppMicroServices Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =============================================================================*/ #include "usConfig.h" #include #include #include #include #include #include #include #include #include #include "stdint_p.h" #include "usConfig.h" #ifdef US_PLATFORM_WINDOWS static const char DIR_SEP = '\\'; #else static const char DIR_SEP = '/'; #endif class ResourceWriter; class Resource { public: enum Flags { NoFlags = 0x00, Directory = 0x01 }; Resource(const std::string& name, const std::string& path = std::string(), unsigned int flags = NoFlags); ~Resource(); std::string GetResourcePath() const; int64_t WriteName(ResourceWriter& writer, int64_t offset); void WriteTreeInfo(ResourceWriter& writer); int64_t WritePayload(ResourceWriter& writer, int64_t offset, std::string* errorMessage); std::string name; std::string path; unsigned int flags; Resource* parent; std::map children; std::map sortedChildren; int64_t nameOffset; int64_t dataOffset; int64_t childOffset; }; class ResourceWriter { public: ResourceWriter(const std::string& fileName, const std::string& libName); ~ResourceWriter(); bool AddFiles(const std::vector& files, const std::string& basePath); bool Write(); private: friend class Resource; bool AddFile(const std::string& alias, const Resource& file); bool WriteHeader(); bool WritePayloads(); bool WriteNames(); bool WriteDataTree(); bool WriteRegistrationCode(); void WriteString(const std::string& str); void WriteChar(char c); void WriteHex(uint8_t tmp); void WriteNumber2(uint16_t number); void WriteNumber4(uint32_t number); std::ofstream out; std::vector files; std::string libName; std::string fileName; Resource* root; }; Resource::Resource(const std::string& name, const std::string& path, unsigned int flags) : name(name) , path(path) , flags(flags) , parent(NULL) , nameOffset(0) , dataOffset(0) , childOffset(0) { } Resource::~Resource() { for (std::map::iterator i = children.begin(); i != children.end(); ++i) { delete i->second; } } std::string Resource::GetResourcePath() const { std::string resource = name; for (Resource* p = parent; p; p = p->parent) { resource = resource.insert(0, p->name + '/'); } return resource; } int64_t Resource::WriteName(ResourceWriter& writer, int64_t offset) { // capture the offset nameOffset = offset; // write the resource name as a comment writer.WriteString(" // "); writer.WriteString(name); writer.WriteString("\n "); // write the length of the name - writer.WriteNumber2(name.size()); + writer.WriteNumber2(static_cast(name.size())); writer.WriteString("\n "); offset += 2; // write the hash value writer.WriteNumber4(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, name))); writer.WriteString("\n "); offset += 4; // write the name itself for (std::size_t i = 0; i < name.length(); ++i) { writer.WriteHex(name[i]); if (i != 0 && i % 32 == 0) writer.WriteString("\n "); } offset += name.length(); // done writer.WriteString("\n "); return offset; } void Resource::WriteTreeInfo(ResourceWriter& writer) { // write the resource path as a comment writer.WriteString(" // "); writer.WriteString(GetResourcePath()); writer.WriteString("\n "); if (flags & Directory) { // name offset (in the us_resource_name array) writer.WriteNumber4(static_cast(nameOffset)); // flags writer.WriteNumber2(flags); // child count - writer.WriteNumber4(children.size()); + writer.WriteNumber4(static_cast(children.size())); // first child offset (in the us_resource_tree array) writer.WriteNumber4(static_cast(childOffset)); } else { // name offset writer.WriteNumber4(static_cast(nameOffset)); // flags writer.WriteNumber2(flags); // padding (not used) writer.WriteNumber4(0); // data offset writer.WriteNumber4(static_cast(dataOffset)); } writer.WriteChar('\n'); } int64_t Resource::WritePayload(ResourceWriter& writer, int64_t offset, std::string* errorMessage) { // capture the offset dataOffset = offset; // open the resource file on the file system std::ifstream file(path.c_str(), std::ifstream::in | std::ifstream::binary); if (!file) { *errorMessage = "File could not be opened: " + path; return 0; } // write the full path of the resource in the file system as a comment writer.WriteString(" // "); writer.WriteString(path); writer.WriteString("\n "); // write the length file.seekg(0, std::ifstream::end); std::ifstream::pos_type size = file.tellg(); file.seekg(0); - writer.WriteNumber4(size); + writer.WriteNumber4(static_cast(size)); writer.WriteString("\n "); offset += 4; // write the actual payload int charsLeft = 16; char c = 0; while (file.get(c)) { --charsLeft; writer.WriteHex(static_cast(c)); if (charsLeft == 0) { writer.WriteString("\n "); charsLeft = 16; } } offset += size; // done writer.WriteString("\n "); return offset; } ResourceWriter::ResourceWriter(const std::string& fileName, const std::string& libName) : libName(libName) , fileName(fileName) , root(NULL) { out.exceptions(std::ofstream::goodbit); out.open(fileName.c_str()); } ResourceWriter::~ResourceWriter() { delete root; } bool ResourceWriter::AddFiles(const std::vector& files, const std::string& basePath) { bool success = true; for (std::size_t i = 0; i < files.size(); ++i) { const std::string& file = files[i]; if (file.size() <= basePath.size() || file.substr(0, basePath.size()) != basePath) { std::cerr << "File " << file << " is not an absolute path starting with " << basePath << std::endl; success = false; } else { const std::string relativePath = file.substr(basePath.size()); std::string name = relativePath; std::size_t index = relativePath.find_last_of(DIR_SEP); if (index != std::string::npos) { name = relativePath.substr(index+1); } success &= AddFile(relativePath, Resource(name, file)); } } return success; } bool ResourceWriter::Write() { if (!WriteHeader()) { std::cerr << "Could not write header." << std::endl; return false; } if (!WritePayloads()) { std::cerr << "Could not write data blobs." << std::endl; return false; } if (!WriteNames()) { std::cerr << "Could not write file names." << std::endl; return false; } if (!WriteDataTree()) { std::cerr << "Could not write data tree." << std::endl; return false; } if (!WriteRegistrationCode()) { std::cerr << "Could not write footer" << std::endl; return false; } return true; } bool ResourceWriter::AddFile(const std::string& alias, const Resource& file) { std::ifstream in(file.path.c_str(), std::ifstream::in | std::ifstream::binary); if (!in) { std::cerr << "File could not be opened: " << file.path << std::endl; return false; } in.seekg(0, std::ifstream::end); std::ifstream::pos_type size = in.tellg(); in.close(); if (size > 0xffffffff) { std::cerr << "File too big: " << file.path << std::endl; return false; } if (!root) { root = new Resource(std::string(), std::string(), Resource::Directory); } Resource* parent = root; std::stringstream ss(alias); std::vector nodes; { std::string node; while (std::getline(ss, node, DIR_SEP)) { if (node.empty()) continue; nodes.push_back(node); } } for(std::size_t i = 0; i < nodes.size()-1; ++i) { const std::string& node = nodes[i]; if (parent->children.find(node) == parent->children.end()) { Resource* s = new Resource(node, std::string(), Resource::Directory); s->parent = parent; parent->children.insert(std::make_pair(node, s)); parent->sortedChildren.insert(std::make_pair(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, node)), s)); parent = s; } else { parent = parent->children[node]; } } const std::string filename = nodes.back(); Resource* s = new Resource(file); s->parent = parent; parent->children.insert(std::make_pair(filename, s)); parent->sortedChildren.insert(std::make_pair(static_cast(US_HASH_FUNCTION_NAMESPACE::US_HASH_FUNCTION(std::string, filename)), s)); return true; } bool ResourceWriter::WriteHeader() { std::stringstream ss; std::time_t now = time(0); ss << std::ctime(&now); WriteString("/*=============================================================================\n"); WriteString(" Resource object code\n"); WriteString("\n"); WriteString(" Created: "); WriteString(ss.str()); WriteString(" by: The Resource Compiler for CppMicroServices version "); WriteString(CppMicroServices_VERSION_STR); WriteString("\n\n"); WriteString(" WARNING! All changes made in this file will be lost!\n"); WriteString( "=============================================================================*/\n\n"); WriteString("#include \n"); WriteString("#include \n\n"); return true; } bool ResourceWriter::WritePayloads() { if (!root) return false; WriteString("static const unsigned char us_resource_data[] = {\n"); std::stack pending; pending.push(root); int64_t offset = 0; std::string errorMessage; while (!pending.empty()) { Resource* file = pending.top(); pending.pop(); for (std::map::iterator i = file->children.begin(); i != file->children.end(); ++i) { Resource* child = i->second; if (child->flags & Resource::Directory) { pending.push(child); } else { offset = child->WritePayload(*this, offset, &errorMessage); if (offset == 0) { std::cerr << errorMessage << std::endl; } } } } WriteString("\n};\n\n"); return true; } bool ResourceWriter::WriteNames() { if (!root) return false; WriteString("static const unsigned char us_resource_name[] = {\n"); std::map names; std::stack pending; pending.push(root); int64_t offset = 0; while (!pending.empty()) { Resource* file = pending.top(); pending.pop(); for (std::map::iterator it = file->children.begin(); it != file->children.end(); ++it) { Resource* child = it->second; if (child->flags & Resource::Directory) { pending.push(child); } if (names.find(child->name) != names.end()) { child->nameOffset = names[child->name]; } else { names.insert(std::make_pair(child->name, offset)); offset = child->WriteName(*this, offset); } } } WriteString("\n};\n\n"); return true; } bool ResourceWriter::WriteDataTree() { if (!root) return false; WriteString("static const unsigned char us_resource_tree[] = {\n"); std::stack pending; // calculate the child offsets in the us_resource_tree array pending.push(root); int offset = 1; while (!pending.empty()) { Resource* file = pending.top(); pending.pop(); file->childOffset = offset; // calculate the offset now for (std::map::iterator i = file->sortedChildren.begin(); i != file->sortedChildren.end(); ++i) { Resource* child = i->second; ++offset; if (child->flags & Resource::Directory) { pending.push(child); } } } // write the tree structure pending.push(root); root->WriteTreeInfo(*this); while (!pending.empty()) { Resource *file = pending.top(); pending.pop(); // write the actual data now for (std::map::iterator i = file->sortedChildren.begin(); i != file->sortedChildren.end(); ++i) { Resource *child = i->second; child->WriteTreeInfo(*this); if (child->flags & Resource::Directory) { pending.push(child); } } } WriteString("\n};\n\n"); return true; } bool ResourceWriter::WriteRegistrationCode() { WriteString("US_BEGIN_NAMESPACE\n\n"); WriteString("extern US_EXPORT bool RegisterResourceData(int, ModuleInfo*, ModuleInfo::ModuleResourceData, ModuleInfo::ModuleResourceData, ModuleInfo::ModuleResourceData);\n\n"); WriteString("US_END_NAMESPACE\n\n"); WriteString(std::string("extern \"C\" US_ABI_EXPORT int _us_init_resources_") + libName + "(US_PREPEND_NAMESPACE(ModuleInfo)* moduleInfo)\n"); WriteString("{\n"); WriteString(" US_PREPEND_NAMESPACE(RegisterResourceData)(0x01, moduleInfo, us_resource_tree, us_resource_name, us_resource_data);\n"); WriteString(" return 1;\n"); WriteString("}\n"); return true; } void ResourceWriter::WriteString(const std::string& str) { out << str; } void ResourceWriter::WriteChar(char c) { out << c; } void ResourceWriter::WriteHex(uint8_t tmp) { const char* const digits = "0123456789abcdef"; WriteChar('0'); WriteChar('x'); if (tmp < 16) { WriteChar(digits[tmp]); } else { WriteChar(digits[tmp >> 4]); WriteChar(digits[tmp & 0xf]); } WriteChar(','); } void ResourceWriter::WriteNumber2(uint16_t number) { WriteHex(number >> 8); WriteHex(static_cast(number)); } void ResourceWriter::WriteNumber4(uint32_t number) { WriteHex(number >> 24); WriteHex(number >> 16); WriteHex(number >> 8); WriteHex(number); } #ifdef US_PLATFORM_POSIX #include std::string GetCurrentDir() { char currDir[512]; if (!getcwd(currDir, sizeof(currDir))) { std::cerr << "Getting the current directory failed." << std::endl; exit(EXIT_FAILURE); } return std::string(currDir); } #else #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include std::string GetCurrentDir() { TCHAR currDir[512]; DWORD dwRet; dwRet = GetCurrentDirectory(sizeof(currDir), currDir); if( dwRet == 0 || dwRet > 512) { std::cerr << "Getting the current directory failed." << std::endl; exit(EXIT_FAILURE); } return std::string(currDir); } #endif int main(int argc, char** argv) { if (argc < 4) { std::cout << US_RCC_EXECUTABLE_NAME " - A resource compiler for C++ Micro Services modules\n" "\n" "Usage: " US_RCC_EXECUTABLE_NAME " LIBNAME OUTPUT INPUT [INPUT]...\n" "Convert all INPUT files into hex code embedded in C funtions written to OUTPUT.\n"; exit(EXIT_SUCCESS); } std::string libName(argv[1]); std::string fileName(argv[2]); std::vector inputFiles; for (int i = 3; i < argc; i++) { inputFiles.push_back(argv[i]); } ResourceWriter writer(fileName, libName); if (!writer.AddFiles(inputFiles, GetCurrentDir())) { return EXIT_FAILURE; } return writer.Write() ? EXIT_SUCCESS : EXIT_FAILURE; }