Mercurial > hg > orthanc
annotate OrthancServer/ServerJobs/ArchiveJob.cpp @ 3116:0fa7181ac4e5 db-changes
conrt
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 12 Jan 2019 11:08:53 +0100 |
parents | beeeb6096f27 |
children | 6fd38327e777 |
rev | line source |
---|---|
2632 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
3060
4e43e67f8ecf
preparing for 2019
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2976
diff
changeset
|
5 * Copyright (C) 2017-2019 Osimis S.A., Belgium |
2632 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "../PrecompiledHeadersServer.h" | |
35 #include "ArchiveJob.h" | |
36 | |
3095
beeeb6096f27
removing dependencies upon ServerContext
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
37 #include "../../Core/Cache/SharedArchive.h" |
2632 | 38 #include "../../Core/Compression/HierarchicalZipWriter.h" |
39 #include "../../Core/DicomParsing/DicomDirWriter.h" | |
40 #include "../../Core/Logging.h" | |
41 #include "../../Core/OrthancException.h" | |
3095
beeeb6096f27
removing dependencies upon ServerContext
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3060
diff
changeset
|
42 #include "../ServerContext.h" |
2632 | 43 |
44 #include <stdio.h> | |
45 | |
46 #if defined(_MSC_VER) | |
47 #define snprintf _snprintf | |
48 #endif | |
49 | |
50 static const uint64_t MEGA_BYTES = 1024 * 1024; | |
51 static const uint64_t GIGA_BYTES = 1024 * 1024 * 1024; | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
52 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
53 static const char* const MEDIA_IMAGES_FOLDER = "IMAGES"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
54 static const char* const KEY_DESCRIPTION = "Description"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
55 static const char* const KEY_INSTANCES_COUNT = "InstancesCount"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
56 static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB"; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
57 |
2632 | 58 |
59 namespace Orthanc | |
60 { | |
61 static bool IsZip64Required(uint64_t uncompressedSize, | |
62 unsigned int countInstances) | |
63 { | |
64 static const uint64_t SAFETY_MARGIN = 64 * MEGA_BYTES; // Should be large enough to hold DICOMDIR | |
65 static const unsigned int FILES_MARGIN = 10; | |
66 | |
67 /** | |
68 * Determine whether ZIP64 is required. Original ZIP format can | |
69 * store up to 2GB of data (some implementation supporting up to | |
70 * 4GB of data), and up to 65535 files. | |
71 * https://en.wikipedia.org/wiki/Zip_(file_format)#ZIP64 | |
72 **/ | |
73 | |
74 const bool isZip64 = (uncompressedSize >= 2 * GIGA_BYTES - SAFETY_MARGIN || | |
75 countInstances >= 65535 - FILES_MARGIN); | |
76 | |
77 LOG(INFO) << "Creating a ZIP file with " << countInstances << " files of size " | |
78 << (uncompressedSize / MEGA_BYTES) << "MB using the " | |
79 << (isZip64 ? "ZIP64" : "ZIP32") << " file format"; | |
80 | |
81 return isZip64; | |
82 } | |
83 | |
84 | |
85 class ArchiveJob::ResourceIdentifiers : public boost::noncopyable | |
86 { | |
87 private: | |
88 ResourceType level_; | |
89 std::string patient_; | |
90 std::string study_; | |
91 std::string series_; | |
92 std::string instance_; | |
93 | |
94 static void GoToParent(ServerIndex& index, | |
95 std::string& current) | |
96 { | |
97 std::string tmp; | |
98 | |
99 if (index.LookupParent(tmp, current)) | |
100 { | |
101 current = tmp; | |
102 } | |
103 else | |
104 { | |
105 throw OrthancException(ErrorCode_UnknownResource); | |
106 } | |
107 } | |
108 | |
109 | |
110 public: | |
111 ResourceIdentifiers(ServerIndex& index, | |
112 const std::string& publicId) | |
113 { | |
114 if (!index.LookupResourceType(level_, publicId)) | |
115 { | |
116 throw OrthancException(ErrorCode_UnknownResource); | |
117 } | |
118 | |
119 std::string current = publicId;; | |
120 switch (level_) // Do not add "break" below! | |
121 { | |
122 case ResourceType_Instance: | |
123 instance_ = current; | |
124 GoToParent(index, current); | |
125 | |
126 case ResourceType_Series: | |
127 series_ = current; | |
128 GoToParent(index, current); | |
129 | |
130 case ResourceType_Study: | |
131 study_ = current; | |
132 GoToParent(index, current); | |
133 | |
134 case ResourceType_Patient: | |
135 patient_ = current; | |
136 break; | |
137 | |
138 default: | |
139 throw OrthancException(ErrorCode_InternalError); | |
140 } | |
141 } | |
142 | |
143 ResourceType GetLevel() const | |
144 { | |
145 return level_; | |
146 } | |
147 | |
148 const std::string& GetIdentifier(ResourceType level) const | |
149 { | |
150 // Some sanity check to ensure enumerations are not altered | |
151 assert(ResourceType_Patient < ResourceType_Study); | |
152 assert(ResourceType_Study < ResourceType_Series); | |
153 assert(ResourceType_Series < ResourceType_Instance); | |
154 | |
155 if (level > level_) | |
156 { | |
157 throw OrthancException(ErrorCode_InternalError); | |
158 } | |
159 | |
160 switch (level) | |
161 { | |
162 case ResourceType_Patient: | |
163 return patient_; | |
164 | |
165 case ResourceType_Study: | |
166 return study_; | |
167 | |
168 case ResourceType_Series: | |
169 return series_; | |
170 | |
171 case ResourceType_Instance: | |
172 return instance_; | |
173 | |
174 default: | |
175 throw OrthancException(ErrorCode_InternalError); | |
176 } | |
177 } | |
178 }; | |
179 | |
180 | |
181 class ArchiveJob::IArchiveVisitor : public boost::noncopyable | |
182 { | |
183 public: | |
184 virtual ~IArchiveVisitor() | |
185 { | |
186 } | |
187 | |
188 virtual void Open(ResourceType level, | |
189 const std::string& publicId) = 0; | |
190 | |
191 virtual void Close() = 0; | |
192 | |
193 virtual void AddInstance(const std::string& instanceId, | |
194 const FileInfo& dicom) = 0; | |
195 }; | |
196 | |
197 | |
198 class ArchiveJob::ArchiveIndex : public boost::noncopyable | |
199 { | |
200 private: | |
201 struct Instance | |
202 { | |
203 std::string id_; | |
204 FileInfo dicom_; | |
205 | |
206 Instance(const std::string& id, | |
207 const FileInfo& dicom) : | |
208 id_(id), dicom_(dicom) | |
209 { | |
210 } | |
211 }; | |
212 | |
213 // A "NULL" value for ArchiveIndex indicates a non-expanded node | |
214 typedef std::map<std::string, ArchiveIndex*> Resources; | |
215 | |
216 ResourceType level_; | |
217 Resources resources_; // Only at patient/study/series level | |
218 std::list<Instance> instances_; // Only at instance level | |
219 | |
220 | |
221 void AddResourceToExpand(ServerIndex& index, | |
222 const std::string& id) | |
223 { | |
224 if (level_ == ResourceType_Instance) | |
225 { | |
226 FileInfo tmp; | |
227 if (index.LookupAttachment(tmp, id, FileContentType_Dicom)) | |
228 { | |
229 instances_.push_back(Instance(id, tmp)); | |
230 } | |
231 } | |
232 else | |
233 { | |
234 resources_[id] = NULL; | |
235 } | |
236 } | |
237 | |
238 | |
239 public: | |
240 ArchiveIndex(ResourceType level) : | |
241 level_(level) | |
242 { | |
243 } | |
244 | |
245 ~ArchiveIndex() | |
246 { | |
247 for (Resources::iterator it = resources_.begin(); | |
248 it != resources_.end(); ++it) | |
249 { | |
250 delete it->second; | |
251 } | |
252 } | |
253 | |
254 | |
255 void Add(ServerIndex& index, | |
256 const ResourceIdentifiers& resource) | |
257 { | |
258 const std::string& id = resource.GetIdentifier(level_); | |
259 Resources::iterator previous = resources_.find(id); | |
260 | |
261 if (level_ == ResourceType_Instance) | |
262 { | |
263 AddResourceToExpand(index, id); | |
264 } | |
265 else if (resource.GetLevel() == level_) | |
266 { | |
267 // Mark this resource for further expansion | |
268 if (previous != resources_.end()) | |
269 { | |
270 delete previous->second; | |
271 } | |
272 | |
273 resources_[id] = NULL; | |
274 } | |
275 else if (previous == resources_.end()) | |
276 { | |
277 // This is the first time we meet this resource | |
278 std::auto_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); | |
279 child->Add(index, resource); | |
280 resources_[id] = child.release(); | |
281 } | |
282 else if (previous->second != NULL) | |
283 { | |
284 previous->second->Add(index, resource); | |
285 } | |
286 else | |
287 { | |
288 // Nothing to do: This item is marked for further expansion | |
289 } | |
290 } | |
291 | |
292 | |
293 void Expand(ServerIndex& index) | |
294 { | |
295 if (level_ == ResourceType_Instance) | |
296 { | |
297 // Expanding an instance node makes no sense | |
298 return; | |
299 } | |
300 | |
301 for (Resources::iterator it = resources_.begin(); | |
302 it != resources_.end(); ++it) | |
303 { | |
304 if (it->second == NULL) | |
305 { | |
306 // This is resource is marked for expansion | |
307 std::list<std::string> children; | |
308 index.GetChildren(children, it->first); | |
309 | |
310 std::auto_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); | |
311 | |
312 for (std::list<std::string>::const_iterator | |
313 it2 = children.begin(); it2 != children.end(); ++it2) | |
314 { | |
315 child->AddResourceToExpand(index, *it2); | |
316 } | |
317 | |
318 it->second = child.release(); | |
319 } | |
320 | |
321 assert(it->second != NULL); | |
322 it->second->Expand(index); | |
323 } | |
324 } | |
325 | |
326 | |
327 void Apply(IArchiveVisitor& visitor) const | |
328 { | |
329 if (level_ == ResourceType_Instance) | |
330 { | |
331 for (std::list<Instance>::const_iterator | |
332 it = instances_.begin(); it != instances_.end(); ++it) | |
333 { | |
334 visitor.AddInstance(it->id_, it->dicom_); | |
335 } | |
336 } | |
337 else | |
338 { | |
339 for (Resources::const_iterator it = resources_.begin(); | |
340 it != resources_.end(); ++it) | |
341 { | |
342 assert(it->second != NULL); // There must have been a call to "Expand()" | |
343 visitor.Open(level_, it->first); | |
344 it->second->Apply(visitor); | |
345 visitor.Close(); | |
346 } | |
347 } | |
348 } | |
349 }; | |
350 | |
351 | |
352 | |
353 class ArchiveJob::ZipCommands : public boost::noncopyable | |
354 { | |
355 private: | |
356 enum Type | |
357 { | |
358 Type_OpenDirectory, | |
359 Type_CloseDirectory, | |
360 Type_WriteInstance | |
361 }; | |
362 | |
363 class Command : public boost::noncopyable | |
364 { | |
365 private: | |
366 Type type_; | |
367 std::string filename_; | |
368 std::string instanceId_; | |
369 FileInfo info_; | |
370 | |
371 public: | |
372 explicit Command(Type type) : | |
373 type_(type) | |
374 { | |
375 assert(type_ == Type_CloseDirectory); | |
376 } | |
377 | |
378 Command(Type type, | |
379 const std::string& filename) : | |
380 type_(type), | |
381 filename_(filename) | |
382 { | |
383 assert(type_ == Type_OpenDirectory); | |
384 } | |
385 | |
386 Command(Type type, | |
387 const std::string& filename, | |
388 const std::string& instanceId, | |
389 const FileInfo& info) : | |
390 type_(type), | |
391 filename_(filename), | |
392 instanceId_(instanceId), | |
393 info_(info) | |
394 { | |
395 assert(type_ == Type_WriteInstance); | |
396 } | |
397 | |
398 void Apply(HierarchicalZipWriter& writer, | |
399 ServerContext& context, | |
400 DicomDirWriter* dicomDir, | |
401 const std::string& dicomDirFolder) const | |
402 { | |
403 switch (type_) | |
404 { | |
405 case Type_OpenDirectory: | |
406 writer.OpenDirectory(filename_.c_str()); | |
407 break; | |
408 | |
409 case Type_CloseDirectory: | |
410 writer.CloseDirectory(); | |
411 break; | |
412 | |
413 case Type_WriteInstance: | |
414 { | |
415 std::string content; | |
416 | |
417 try | |
418 { | |
419 context.ReadAttachment(content, info_); | |
420 } | |
421 catch (OrthancException& e) | |
422 { | |
423 LOG(WARNING) << "An instance was removed after the job was issued: " << instanceId_; | |
424 return; | |
425 } | |
2636 | 426 |
427 //boost::this_thread::sleep(boost::posix_time::milliseconds(300)); | |
2632 | 428 |
429 writer.OpenFile(filename_.c_str()); | |
430 writer.Write(content); | |
431 | |
432 if (dicomDir != NULL) | |
433 { | |
434 ParsedDicomFile parsed(content); | |
435 dicomDir->Add(dicomDirFolder, filename_, parsed); | |
436 } | |
437 | |
438 break; | |
439 } | |
440 | |
441 default: | |
442 throw OrthancException(ErrorCode_InternalError); | |
443 } | |
444 } | |
445 }; | |
446 | |
447 std::deque<Command*> commands_; | |
448 uint64_t uncompressedSize_; | |
449 unsigned int instancesCount_; | |
450 | |
451 | |
452 void ApplyInternal(HierarchicalZipWriter& writer, | |
453 ServerContext& context, | |
454 size_t index, | |
455 DicomDirWriter* dicomDir, | |
456 const std::string& dicomDirFolder) const | |
457 { | |
458 if (index >= commands_.size()) | |
459 { | |
460 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
461 } | |
462 | |
463 commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder); | |
464 } | |
465 | |
466 public: | |
467 ZipCommands() : | |
468 uncompressedSize_(0), | |
469 instancesCount_(0) | |
470 { | |
471 } | |
472 | |
473 ~ZipCommands() | |
474 { | |
475 for (std::deque<Command*>::iterator it = commands_.begin(); | |
476 it != commands_.end(); ++it) | |
477 { | |
478 assert(*it != NULL); | |
479 delete *it; | |
480 } | |
481 } | |
482 | |
483 size_t GetSize() const | |
484 { | |
485 return commands_.size(); | |
486 } | |
487 | |
488 unsigned int GetInstancesCount() const | |
489 { | |
490 return instancesCount_; | |
491 } | |
492 | |
493 uint64_t GetUncompressedSize() const | |
494 { | |
495 return uncompressedSize_; | |
496 } | |
497 | |
498 void Apply(HierarchicalZipWriter& writer, | |
499 ServerContext& context, | |
500 size_t index, | |
501 DicomDirWriter& dicomDir, | |
502 const std::string& dicomDirFolder) const | |
503 { | |
504 ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder); | |
505 } | |
506 | |
507 void Apply(HierarchicalZipWriter& writer, | |
508 ServerContext& context, | |
509 size_t index) const | |
510 { | |
511 ApplyInternal(writer, context, index, NULL, ""); | |
512 } | |
513 | |
514 void AddOpenDirectory(const std::string& filename) | |
515 { | |
516 commands_.push_back(new Command(Type_OpenDirectory, filename)); | |
517 } | |
518 | |
519 void AddCloseDirectory() | |
520 { | |
521 commands_.push_back(new Command(Type_CloseDirectory)); | |
522 } | |
523 | |
524 void AddWriteInstance(const std::string& filename, | |
525 const std::string& instanceId, | |
526 const FileInfo& info) | |
527 { | |
528 commands_.push_back(new Command(Type_WriteInstance, filename, instanceId, info)); | |
529 instancesCount_ ++; | |
530 uncompressedSize_ += info.GetUncompressedSize(); | |
531 } | |
532 | |
533 bool IsZip64() const | |
534 { | |
535 return IsZip64Required(GetUncompressedSize(), GetInstancesCount()); | |
536 } | |
537 }; | |
538 | |
539 | |
540 | |
541 class ArchiveJob::ArchiveIndexVisitor : public IArchiveVisitor | |
542 { | |
543 private: | |
544 ZipCommands& commands_; | |
545 ServerContext& context_; | |
546 char instanceFormat_[24]; | |
547 unsigned int counter_; | |
548 | |
549 static std::string GetTag(const DicomMap& tags, | |
550 const DicomTag& tag) | |
551 { | |
552 const DicomValue* v = tags.TestAndGetValue(tag); | |
553 if (v != NULL && | |
554 !v->IsBinary() && | |
555 !v->IsNull()) | |
556 { | |
557 return v->GetContent(); | |
558 } | |
559 else | |
560 { | |
561 return ""; | |
562 } | |
563 } | |
564 | |
565 public: | |
566 ArchiveIndexVisitor(ZipCommands& commands, | |
567 ServerContext& context) : | |
568 commands_(commands), | |
569 context_(context), | |
570 counter_(0) | |
571 { | |
572 if (commands.GetSize() != 0) | |
573 { | |
574 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
575 } | |
576 | |
577 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); | |
578 } | |
579 | |
580 virtual void Open(ResourceType level, | |
581 const std::string& publicId) | |
582 { | |
583 std::string path; | |
584 | |
585 DicomMap tags; | |
586 if (context_.GetIndex().GetMainDicomTags(tags, publicId, level, level)) | |
587 { | |
588 switch (level) | |
589 { | |
590 case ResourceType_Patient: | |
591 path = GetTag(tags, DICOM_TAG_PATIENT_ID) + " " + GetTag(tags, DICOM_TAG_PATIENT_NAME); | |
592 break; | |
593 | |
594 case ResourceType_Study: | |
595 path = GetTag(tags, DICOM_TAG_ACCESSION_NUMBER) + " " + GetTag(tags, DICOM_TAG_STUDY_DESCRIPTION); | |
596 break; | |
597 | |
598 case ResourceType_Series: | |
599 { | |
600 std::string modality = GetTag(tags, DICOM_TAG_MODALITY); | |
601 path = modality + " " + GetTag(tags, DICOM_TAG_SERIES_DESCRIPTION); | |
602 | |
603 if (modality.size() == 0) | |
604 { | |
605 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); | |
606 } | |
607 else if (modality.size() == 1) | |
608 { | |
609 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%c%%07d.dcm", | |
610 toupper(modality[0])); | |
611 } | |
612 else if (modality.size() >= 2) | |
613 { | |
614 snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%c%c%%06d.dcm", | |
615 toupper(modality[0]), toupper(modality[1])); | |
616 } | |
617 | |
618 counter_ = 0; | |
619 | |
620 break; | |
621 } | |
622 | |
623 default: | |
624 throw OrthancException(ErrorCode_InternalError); | |
625 } | |
626 } | |
627 | |
628 path = Toolbox::StripSpaces(Toolbox::ConvertToAscii(path)); | |
629 | |
630 if (path.empty()) | |
631 { | |
632 path = std::string("Unknown ") + EnumerationToString(level); | |
633 } | |
634 | |
635 commands_.AddOpenDirectory(path.c_str()); | |
636 } | |
637 | |
638 virtual void Close() | |
639 { | |
640 commands_.AddCloseDirectory(); | |
641 } | |
642 | |
643 virtual void AddInstance(const std::string& instanceId, | |
644 const FileInfo& dicom) | |
645 { | |
646 char filename[24]; | |
647 snprintf(filename, sizeof(filename) - 1, instanceFormat_, counter_); | |
648 counter_ ++; | |
649 | |
650 commands_.AddWriteInstance(filename, instanceId, dicom); | |
651 } | |
652 }; | |
653 | |
654 | |
655 class ArchiveJob::MediaIndexVisitor : public IArchiveVisitor | |
656 { | |
657 private: | |
658 ZipCommands& commands_; | |
659 ServerContext& context_; | |
660 unsigned int counter_; | |
661 | |
662 public: | |
663 MediaIndexVisitor(ZipCommands& commands, | |
664 ServerContext& context) : | |
665 commands_(commands), | |
666 context_(context), | |
667 counter_(0) | |
668 { | |
669 } | |
670 | |
671 virtual void Open(ResourceType level, | |
672 const std::string& publicId) | |
673 { | |
674 } | |
675 | |
676 virtual void Close() | |
677 { | |
678 } | |
679 | |
680 virtual void AddInstance(const std::string& instanceId, | |
681 const FileInfo& dicom) | |
682 { | |
683 // "DICOM restricts the filenames on DICOM media to 8 | |
684 // characters (some systems wrongly use 8.3, but this does not | |
685 // conform to the standard)." | |
686 std::string filename = "IM" + boost::lexical_cast<std::string>(counter_); | |
687 commands_.AddWriteInstance(filename, instanceId, dicom); | |
688 | |
689 counter_ ++; | |
690 } | |
691 }; | |
692 | |
693 | |
694 class ArchiveJob::ZipWriterIterator : public boost::noncopyable | |
695 { | |
696 private: | |
697 TemporaryFile& target_; | |
698 ServerContext& context_; | |
699 ZipCommands commands_; | |
700 std::auto_ptr<HierarchicalZipWriter> zip_; | |
701 std::auto_ptr<DicomDirWriter> dicomDir_; | |
702 bool isMedia_; | |
703 | |
704 public: | |
705 ZipWriterIterator(TemporaryFile& target, | |
706 ServerContext& context, | |
707 ArchiveIndex& archive, | |
708 bool isMedia, | |
709 bool enableExtendedSopClass) : | |
710 target_(target), | |
711 context_(context), | |
712 isMedia_(isMedia) | |
713 { | |
714 if (isMedia) | |
715 { | |
716 MediaIndexVisitor visitor(commands_, context); | |
717 archive.Expand(context.GetIndex()); | |
718 | |
719 commands_.AddOpenDirectory(MEDIA_IMAGES_FOLDER); | |
720 archive.Apply(visitor); | |
721 commands_.AddCloseDirectory(); | |
722 | |
723 dicomDir_.reset(new DicomDirWriter); | |
724 dicomDir_->EnableExtendedSopClass(enableExtendedSopClass); | |
725 } | |
726 else | |
727 { | |
728 ArchiveIndexVisitor visitor(commands_, context); | |
729 archive.Expand(context.GetIndex()); | |
730 archive.Apply(visitor); | |
731 } | |
732 | |
733 zip_.reset(new HierarchicalZipWriter(target.GetPath().c_str())); | |
734 zip_->SetZip64(commands_.IsZip64()); | |
735 } | |
736 | |
737 size_t GetStepsCount() const | |
738 { | |
739 return commands_.GetSize() + 1; | |
740 } | |
741 | |
742 void RunStep(size_t index) | |
743 { | |
744 if (index > commands_.GetSize()) | |
745 { | |
746 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
747 } | |
748 else if (index == commands_.GetSize()) | |
749 { | |
750 // Last step: Add the DICOMDIR | |
751 if (isMedia_) | |
752 { | |
753 assert(dicomDir_.get() != NULL); | |
754 std::string s; | |
755 dicomDir_->Encode(s); | |
756 | |
757 zip_->OpenFile("DICOMDIR"); | |
758 zip_->Write(s); | |
759 } | |
760 } | |
761 else | |
762 { | |
763 if (isMedia_) | |
764 { | |
765 assert(dicomDir_.get() != NULL); | |
766 commands_.Apply(*zip_, context_, index, *dicomDir_, MEDIA_IMAGES_FOLDER); | |
767 } | |
768 else | |
769 { | |
770 assert(dicomDir_.get() == NULL); | |
771 commands_.Apply(*zip_, context_, index); | |
772 } | |
773 } | |
774 } | |
775 | |
776 unsigned int GetInstancesCount() const | |
777 { | |
778 return commands_.GetInstancesCount(); | |
779 } | |
780 | |
781 uint64_t GetUncompressedSize() const | |
782 { | |
783 return commands_.GetUncompressedSize(); | |
784 } | |
785 }; | |
786 | |
787 | |
2966 | 788 ArchiveJob::ArchiveJob(ServerContext& context, |
2632 | 789 bool isMedia, |
790 bool enableExtendedSopClass) : | |
791 context_(context), | |
792 archive_(new ArchiveIndex(ResourceType_Patient)), // root | |
793 isMedia_(isMedia), | |
794 enableExtendedSopClass_(enableExtendedSopClass), | |
795 currentStep_(0), | |
796 instancesCount_(0), | |
797 uncompressedSize_(0) | |
798 { | |
2966 | 799 } |
800 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
801 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
802 ArchiveJob::~ArchiveJob() |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
803 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
804 if (!mediaArchiveId_.empty()) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
805 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
806 context_.GetMediaArchive().Remove(mediaArchiveId_); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
807 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
808 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
809 |
2966 | 810 |
811 void ArchiveJob::SetSynchronousTarget(boost::shared_ptr<TemporaryFile>& target) | |
812 { | |
813 if (target.get() == NULL) | |
2632 | 814 { |
815 throw OrthancException(ErrorCode_NullPointer); | |
816 } | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
817 else if (writer_.get() != NULL || // Already started |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
818 synchronousTarget_.get() != NULL || |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
819 asynchronousTarget_.get() != NULL) |
2966 | 820 { |
821 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
822 } | |
823 else | |
824 { | |
825 synchronousTarget_ = target; | |
826 } | |
2632 | 827 } |
828 | |
829 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
830 void ArchiveJob::SetDescription(const std::string& description) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
831 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
832 if (writer_.get() != NULL) // Already started |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
833 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
834 throw OrthancException(ErrorCode_BadSequenceOfCalls); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
835 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
836 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
837 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
838 description_ = description; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
839 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
840 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
841 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
842 |
2632 | 843 void ArchiveJob::AddResource(const std::string& publicId) |
844 { | |
845 if (writer_.get() != NULL) // Already started | |
846 { | |
847 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
848 } | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
849 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
850 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
851 ResourceIdentifiers resource(context_.GetIndex(), publicId); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
852 archive_->Add(context_.GetIndex(), resource); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
853 } |
2632 | 854 } |
855 | |
856 | |
2812
ea7aea6f6a95
improved naming of methods in IJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2730
diff
changeset
|
857 void ArchiveJob::Reset() |
2632 | 858 { |
2955 | 859 throw OrthancException(ErrorCode_BadSequenceOfCalls, |
860 "Cannot resubmit the creation of an archive"); | |
2632 | 861 } |
862 | |
863 | |
864 void ArchiveJob::Start() | |
865 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
866 TemporaryFile* target = NULL; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
867 |
2966 | 868 if (synchronousTarget_.get() == NULL) |
869 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
870 asynchronousTarget_.reset(new TemporaryFile); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
871 target = asynchronousTarget_.get(); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
872 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
873 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
874 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
875 target = synchronousTarget_.get(); |
2966 | 876 } |
877 | |
2632 | 878 if (writer_.get() != NULL) |
879 { | |
880 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
881 } | |
882 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
883 writer_.reset(new ZipWriterIterator(*target, context_, *archive_, |
2632 | 884 isMedia_, enableExtendedSopClass_)); |
885 | |
886 instancesCount_ = writer_->GetInstancesCount(); | |
887 uncompressedSize_ = writer_->GetUncompressedSize(); | |
888 } | |
889 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
890 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
891 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
892 namespace |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
893 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
894 class DynamicTemporaryFile : public IDynamicObject |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
895 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
896 private: |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
897 std::auto_ptr<TemporaryFile> file_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
898 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
899 public: |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
900 DynamicTemporaryFile(TemporaryFile* f) : file_(f) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
901 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
902 if (f == NULL) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
903 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
904 throw OrthancException(ErrorCode_NullPointer); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
905 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
906 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
907 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
908 const TemporaryFile& GetFile() const |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
909 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
910 assert(file_.get() != NULL); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
911 return *file_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
912 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
913 }; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
914 } |
2632 | 915 |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
916 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
917 void ArchiveJob::FinalizeTarget() |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
918 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
919 writer_.reset(); // Flush all the results |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
920 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
921 if (asynchronousTarget_.get() != NULL) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
922 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
923 // Asynchronous behavior: Move the resulting file into the media archive |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
924 mediaArchiveId_ = context_.GetMediaArchive().Add( |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
925 new DynamicTemporaryFile(asynchronousTarget_.release())); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
926 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
927 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
928 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
929 |
2812
ea7aea6f6a95
improved naming of methods in IJob
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2730
diff
changeset
|
930 JobStepResult ArchiveJob::Step() |
2632 | 931 { |
932 assert(writer_.get() != NULL); | |
933 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
934 if (synchronousTarget_.get() != NULL && |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
935 synchronousTarget_.unique()) |
2632 | 936 { |
937 LOG(WARNING) << "A client has disconnected while creating an archive"; | |
938 return JobStepResult::Failure(ErrorCode_NetworkProtocol); | |
939 } | |
940 | |
941 if (writer_->GetStepsCount() == 0) | |
942 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
943 FinalizeTarget(); |
2632 | 944 return JobStepResult::Success(); |
945 } | |
946 else | |
947 { | |
948 writer_->RunStep(currentStep_); | |
949 | |
950 currentStep_ ++; | |
951 | |
952 if (currentStep_ == writer_->GetStepsCount()) | |
953 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
954 FinalizeTarget(); |
2632 | 955 return JobStepResult::Success(); |
956 } | |
957 else | |
958 { | |
959 return JobStepResult::Continue(); | |
960 } | |
961 } | |
962 } | |
963 | |
964 | |
965 float ArchiveJob::GetProgress() | |
966 { | |
967 if (writer_.get() == NULL || | |
968 writer_->GetStepsCount() == 0) | |
969 { | |
970 return 1; | |
971 } | |
972 else | |
973 { | |
974 return (static_cast<float>(currentStep_) / | |
975 static_cast<float>(writer_->GetStepsCount() - 1)); | |
976 } | |
977 } | |
978 | |
979 | |
980 void ArchiveJob::GetJobType(std::string& target) | |
981 { | |
982 if (isMedia_) | |
983 { | |
984 target = "Media"; | |
985 } | |
986 else | |
987 { | |
988 target = "Archive"; | |
989 } | |
990 } | |
991 | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
992 |
2632 | 993 void ArchiveJob::GetPublicContent(Json::Value& value) |
994 { | |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
995 value = Json::objectValue; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
996 value[KEY_DESCRIPTION] = description_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
997 value[KEY_INSTANCES_COUNT] = instancesCount_; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
998 value[KEY_UNCOMPRESSED_SIZE_MB] = |
2643 | 999 static_cast<unsigned int>(uncompressedSize_ / MEGA_BYTES); |
2632 | 1000 } |
2976
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1001 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1002 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1003 bool ArchiveJob::GetOutput(std::string& output, |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1004 MimeType& mime, |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1005 const std::string& key) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1006 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1007 if (key == "archive" && |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1008 !mediaArchiveId_.empty()) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1009 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1010 SharedArchive::Accessor accessor(context_.GetMediaArchive(), mediaArchiveId_); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1011 |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1012 if (accessor.IsValid()) |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1013 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1014 const DynamicTemporaryFile& f = dynamic_cast<DynamicTemporaryFile&>(accessor.GetItem()); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1015 f.GetFile().Read(output); |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1016 mime = MimeType_Zip; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1017 return true; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1018 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1019 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1020 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1021 return false; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1022 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1023 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1024 else |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1025 { |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1026 return false; |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1027 } |
cb5d75143da0
Asynchronous generation of ZIP archives and DICOM medias
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2966
diff
changeset
|
1028 } |
2632 | 1029 } |