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