Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
usModuleResourceContainer.cpp
Go to the documentation of this file.
1 /*=============================================================================
2 
3  Library: CppMicroServices
4 
5  Copyright (c) German Cancer Research Center,
6  Division of Medical and Biological Informatics
7 
8  Licensed under the Apache License, Version 2.0 (the "License");
9  you may not use this file except in compliance with the License.
10  You may obtain a copy of the License at
11 
12  http://www.apache.org/licenses/LICENSE-2.0
13 
14  Unless required by applicable law or agreed to in writing, software
15  distributed under the License is distributed on an "AS IS" BASIS,
16  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  See the License for the specific language governing permissions and
18  limitations under the License.
19 
20 =============================================================================*/
21 
22 #include "usModuleResourceContainer_p.h"
23 
24 #include "usModuleInfo.h"
25 #include "usModuleUtils_p.h"
26 #include "usModuleResource.h"
27 #include "usLog_p.h"
28 
29 #include "miniz.h"
30 
31 #include <set>
32 #include <cstring>
33 #include <climits>
34 #include <cassert>
35 
36 US_BEGIN_NAMESPACE
37 
38 struct ModuleResourceContainerPrivate
39 {
40  ModuleResourceContainerPrivate(const ModuleInfo* moduleInfo)
41  : m_ModuleInfo(moduleInfo)
42  , m_IsValid(false)
43  , m_ZipArchive()
44  {}
45 
46  typedef std::pair<std::string, int> NameIndexPair;
47 
48  struct PairComp
49  {
50  bool operator()(const NameIndexPair& p1, const NameIndexPair& p2) const
51  {
52  return p1.first < p2.first;
53  }
54  };
55 
56  typedef std::set<NameIndexPair, PairComp> SetType;
57 
58  void InitSortedEntries()
59  {
60  if (m_SortedEntries.empty())
61  {
62  mz_uint numFiles = mz_zip_reader_get_num_files(&m_ZipArchive);
63  for (mz_uint fileIndex = 0; fileIndex < numFiles; ++fileIndex)
64  {
65  char fileName[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
66  mz_zip_reader_get_filename(&m_ZipArchive, fileIndex, fileName, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE);
67  m_SortedEntries.insert(std::make_pair(std::string(fileName), fileIndex));
68  }
69  }
70  }
71 
72  const ModuleInfo* m_ModuleInfo;
73  bool m_IsValid;
74 
75  mz_zip_archive m_ZipArchive;
76 
77  std::set<NameIndexPair, PairComp> m_SortedEntries;
78 };
79 
80 ModuleResourceContainer::ModuleResourceContainer(const ModuleInfo* moduleInfo)
81  : d(new ModuleResourceContainerPrivate(moduleInfo))
82 {
83  if (mz_zip_reader_init_file(&d->m_ZipArchive, moduleInfo->location.c_str(), 0))
84  {
85  d->m_IsValid = true;
86  }
87  else
88  {
89  US_DEBUG << "Could not init zip archive for module " << moduleInfo->name;
90  }
91 }
92 
93 ModuleResourceContainer::~ModuleResourceContainer()
94 {
95  if (IsValid())
96  {
97  mz_zip_reader_end(&d->m_ZipArchive);
98  }
99  delete d;
100 }
101 
102 bool ModuleResourceContainer::IsValid() const
103 {
104  return d->m_IsValid;
105 }
106 
107 bool ModuleResourceContainer::GetStat(ModuleResourceContainer::Stat& stat) const
108 {
109  if (IsValid())
110  {
111  int fileIndex = mz_zip_reader_locate_file(&d->m_ZipArchive, stat.filePath.c_str(), NULL, 0);
112  if (fileIndex >= 0)
113  {
114  return GetStat(fileIndex, stat);
115  }
116  }
117  return false;
118 }
119 
120 bool ModuleResourceContainer::GetStat(int index, ModuleResourceContainer::Stat& stat) const
121 {
122  if (IsValid())
123  {
124  if (index >= 0)
125  {
126  mz_zip_archive_file_stat zipStat;
127  if (!mz_zip_reader_file_stat(&d->m_ZipArchive, index, &zipStat))
128  {
129  return false;
130  }
131  stat.index = index;
132  stat.filePath = zipStat.m_filename;
133  stat.isDir = mz_zip_reader_is_file_a_directory(&d->m_ZipArchive, index) ? true : false;
134  stat.modifiedTime = zipStat.m_time;
135  // This will limit the size info from uint64 to uint32 on 32-bit
136  // architectures. We don't care because we assume resources > 2GB
137  // don't make sense to be embedded in a module anyway.
138  assert(zipStat.m_comp_size < INT_MAX);
139  assert(zipStat.m_uncomp_size < INT_MAX);
140  stat.uncompressedSize = static_cast<int>(zipStat.m_uncomp_size);
141  return true;
142  }
143  }
144  return false;
145 }
146 
147 void* ModuleResourceContainer::GetData(int index) const
148 {
149  return mz_zip_reader_extract_to_heap(&d->m_ZipArchive, index, NULL, 0);
150 }
151 
152 const ModuleInfo*ModuleResourceContainer::GetModuleInfo() const
153 {
154  return d->m_ModuleInfo;
155 }
156 
157 void ModuleResourceContainer::GetChildren(const std::string& resourcePath, bool relativePaths,
158  std::vector<std::string>& names, std::vector<uint32_t>& indices) const
159 {
160  d->InitSortedEntries();
161 
162  ModuleResourceContainerPrivate::SetType::const_iterator iter =
163  d->m_SortedEntries.find(std::make_pair(resourcePath, 0));
164  if (iter == d->m_SortedEntries.end())
165  {
166  return;
167  }
168 
169  for (++iter; iter != d->m_SortedEntries.end(); ++iter)
170  {
171  if (resourcePath.size() > iter->first.size()) break;
172  if (iter->first.compare(0, resourcePath.size(), resourcePath) == 0)
173  {
174  std::size_t pos = iter->first.find_first_of('/', resourcePath.size());
175  if (pos == std::string::npos || pos == iter->first.size()-1)
176  {
177  if (relativePaths)
178  {
179  names.push_back(iter->first.substr(resourcePath.size()));
180  }
181  else
182  {
183  names.push_back(iter->first);
184  }
185  indices.push_back(iter->second);
186  }
187  }
188  }
189 }
190 
191 void ModuleResourceContainer::FindNodes(const std::string& path, const std::string& filePattern,
192  bool recurse, std::vector<ModuleResource>& resources) const
193 {
194  std::vector<std::string> names;
195  std::vector<uint32_t> indices;
196 
197  this->GetChildren(path, true, names, indices);
198 
199  for(std::size_t i = 0, s = names.size(); i < s; ++i)
200  {
201  if (*names[i].rbegin() == '/' && recurse)
202  {
203  this->FindNodes(path + names[i], filePattern, recurse, resources);
204  }
205  if (this->Matches(names[i], filePattern))
206  {
207  resources.push_back(ModuleResource(indices[i], *this));
208  }
209  }
210 }
211 
212 bool ModuleResourceContainer::Matches(const std::string& name, const std::string& filePattern) const
213 {
214  // short-cut
215  if (filePattern == "*") return true;
216 
217  std::stringstream ss(filePattern);
218  std::string tok;
219  std::size_t pos = 0;
220  while(std::getline(ss, tok, '*'))
221  {
222  std::size_t index = name.find(tok, pos);
223  if (index == std::string::npos) return false;
224  pos = index + tok.size();
225  }
226  return true;
227 }
228 
229 US_END_NAMESPACE
T::Pointer GetData(const std::string &name)