1 /*****************************************************************************/
2 // Copyright 2006-2007 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8
9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_stream.cpp#2 $ */
10 /* $DateTime: 2012/06/01 07:28:57 $ */
11 /* $Change: 832715 $ */
12 /* $Author: tknoll $ */
13
14 /*****************************************************************************/
15
16 #include "dng_stream.h"
17
18 #include "dng_abort_sniffer.h"
19 #include "dng_auto_ptr.h"
20 #include "dng_bottlenecks.h"
21 #include "dng_exceptions.h"
22 #include "dng_flags.h"
23 #include "dng_memory.h"
24 #include "dng_tag_types.h"
25
26 /*****************************************************************************/
27
dng_stream(dng_abort_sniffer * sniffer,uint32 bufferSize,uint64 offsetInOriginalFile)28 dng_stream::dng_stream (dng_abort_sniffer *sniffer,
29 uint32 bufferSize,
30 uint64 offsetInOriginalFile)
31
32 : fSwapBytes (false)
33 , fHaveLength (false)
34 , fLength (0)
35 , fOffsetInOriginalFile (offsetInOriginalFile)
36 , fPosition (0)
37 , fMemBlock (bufferSize)
38 , fBuffer (fMemBlock.Buffer_uint8 ())
39 , fBufferSize (bufferSize)
40 , fBufferStart (0)
41 , fBufferEnd (0)
42 , fBufferLimit (bufferSize)
43 , fBufferDirty (false)
44 , fSniffer (sniffer)
45
46 {
47
48 }
49
50 /*****************************************************************************/
51
dng_stream(const void * data,uint32 count,uint64 offsetInOriginalFile)52 dng_stream::dng_stream (const void *data,
53 uint32 count,
54 uint64 offsetInOriginalFile)
55
56 : fSwapBytes (false)
57 , fHaveLength (true)
58 , fLength (count)
59 , fOffsetInOriginalFile (offsetInOriginalFile)
60 , fPosition (0)
61 , fMemBlock ()
62 , fBuffer ((uint8 *) data)
63 , fBufferSize (count)
64 , fBufferStart (0)
65 , fBufferEnd (count)
66 , fBufferLimit (count)
67 , fBufferDirty (false)
68 , fSniffer (NULL)
69
70 {
71
72 }
73
74 /*****************************************************************************/
75
~dng_stream()76 dng_stream::~dng_stream ()
77 {
78
79 }
80
81 /*****************************************************************************/
82
DoGetLength()83 uint64 dng_stream::DoGetLength ()
84 {
85
86 ThrowProgramError ();
87
88 return 0;
89
90 }
91
92 /*****************************************************************************/
93
DoRead(void *,uint32,uint64)94 void dng_stream::DoRead (void * /* data */,
95 uint32 /* count */,
96 uint64 /* offset */)
97 {
98
99 ThrowProgramError ();
100
101 }
102
103 /*****************************************************************************/
104
DoSetLength(uint64)105 void dng_stream::DoSetLength (uint64 /* length */)
106 {
107
108 ThrowProgramError ();
109
110 }
111
112 /*****************************************************************************/
113
DoWrite(const void *,uint32,uint64)114 void dng_stream::DoWrite (const void * /* data */,
115 uint32 /* count */,
116 uint64 /* offset */)
117 {
118
119 ThrowProgramError ();
120
121 }
122
123 /*****************************************************************************/
124
BigEndian() const125 bool dng_stream::BigEndian () const
126 {
127
128 return fSwapBytes != (!!qDNGBigEndian);
129
130 }
131
132 /*****************************************************************************/
133
SetBigEndian(bool bigEndian)134 void dng_stream::SetBigEndian (bool bigEndian)
135 {
136
137 fSwapBytes = (bigEndian != (!!qDNGBigEndian));
138
139 }
140
141 /*****************************************************************************/
142
Data() const143 const void * dng_stream::Data () const
144 {
145
146 if (fBufferStart == 0 && fHaveLength && fBufferEnd == fLength)
147 {
148
149 return fBuffer;
150
151 }
152
153 return NULL;
154
155 }
156
157 /*****************************************************************************/
158
AsMemoryBlock(dng_memory_allocator & allocator)159 dng_memory_block * dng_stream::AsMemoryBlock (dng_memory_allocator &allocator)
160 {
161
162 Flush ();
163
164 uint64 len64 = Length ();
165
166 if (len64 > 0xFFFFFFFF)
167 {
168 ThrowProgramError ();
169 }
170
171 uint32 len = (uint32) len64;
172
173 AutoPtr<dng_memory_block> block (allocator.Allocate (len));
174
175 if (len)
176 {
177
178 SetReadPosition (0);
179
180 Get (block->Buffer (), len);
181
182 }
183
184 return block.Release ();
185
186 }
187
188 /*****************************************************************************/
189
SetReadPosition(uint64 offset)190 void dng_stream::SetReadPosition (uint64 offset)
191 {
192
193 fPosition = offset;
194
195 if (fPosition > Length ())
196 {
197
198 ThrowEndOfFile ();
199
200 }
201
202 }
203
204 /*****************************************************************************/
205
OffsetInOriginalFile() const206 uint64 dng_stream::OffsetInOriginalFile () const
207 {
208
209 return fOffsetInOriginalFile;
210
211 }
212
213 /*****************************************************************************/
214
PositionInOriginalFile() const215 uint64 dng_stream::PositionInOriginalFile () const
216 {
217
218 if (fOffsetInOriginalFile == kDNGStreamInvalidOffset)
219 return kDNGStreamInvalidOffset;
220
221 return fOffsetInOriginalFile + Position ();
222
223 }
224
225 /*****************************************************************************/
226
Get(void * data,uint32 count)227 void dng_stream::Get (void *data, uint32 count)
228 {
229
230 while (count)
231 {
232
233 // See if the request is totally inside buffer.
234
235 if (fPosition >= fBufferStart && fPosition + count <= fBufferEnd)
236 {
237
238 DoCopyBytes (fBuffer + (uint32) (fPosition - fBufferStart),
239 data,
240 count);
241
242 fPosition += count;
243
244 return;
245
246 }
247
248 // See if first part of request is inside buffer.
249
250 if (fPosition >= fBufferStart && fPosition < fBufferEnd)
251 {
252
253 uint32 block = (uint32) (fBufferEnd - fPosition);
254
255 DoCopyBytes (fBuffer + (fPosition - fBufferStart),
256 data,
257 block);
258
259 count -= block;
260
261 data = (void *) (((char *) data) + block);
262
263 fPosition += block;
264
265 }
266
267 // Flush buffer if dirty.
268
269 Flush ();
270
271 // Do large reads unbuffered.
272
273 if (count > fBufferSize)
274 {
275
276 if (fPosition + count > Length ())
277 {
278
279 ThrowEndOfFile ();
280
281 }
282
283 DoRead (data,
284 count,
285 fPosition);
286
287 fPosition += count;
288
289 return;
290
291 }
292
293 // Figure out new buffer range.
294
295 fBufferStart = fPosition;
296
297 if (fBufferSize >= 4096)
298 {
299
300 // Align to a 4K file block.
301
302 fBufferStart &= (uint64) ~((int64) 4095);
303
304 }
305
306 fBufferEnd = Min_uint64 (fBufferStart + fBufferSize, Length ());
307
308 if (fBufferEnd <= fPosition)
309 {
310
311 ThrowEndOfFile ();
312
313 }
314
315 // Read data into buffer.
316
317 dng_abort_sniffer::SniffForAbort (fSniffer);
318
319 DoRead (fBuffer,
320 (uint32) (fBufferEnd - fBufferStart),
321 fBufferStart);
322
323 }
324
325 }
326
327 /*****************************************************************************/
328
SetWritePosition(uint64 offset)329 void dng_stream::SetWritePosition (uint64 offset)
330 {
331
332 fPosition = offset;
333
334 }
335
336 /*****************************************************************************/
337
Flush()338 void dng_stream::Flush ()
339 {
340
341 if (fBufferDirty)
342 {
343
344 dng_abort_sniffer::SniffForAbort (fSniffer);
345
346 DoWrite (fBuffer,
347 (uint32) (fBufferEnd - fBufferStart),
348 fBufferStart);
349
350 fBufferStart = 0;
351 fBufferEnd = 0;
352 fBufferLimit = fBufferSize;
353
354 fBufferDirty = false;
355
356 }
357
358 }
359
360 /*****************************************************************************/
361
SetLength(uint64 length)362 void dng_stream::SetLength (uint64 length)
363 {
364
365 Flush ();
366
367 if (Length () != length)
368 {
369
370 DoSetLength (length);
371
372 fLength = length;
373
374 }
375
376 }
377
378 /*****************************************************************************/
379
Put(const void * data,uint32 count)380 void dng_stream::Put (const void *data,
381 uint32 count)
382 {
383
384 // See if we can replace or append to the existing buffer.
385
386 uint64 endPosition = fPosition + count;
387
388 if (fBufferDirty &&
389 fPosition >= fBufferStart &&
390 fPosition <= fBufferEnd &&
391 endPosition <= fBufferLimit)
392 {
393
394 DoCopyBytes (data,
395 fBuffer + (uint32) (fPosition - fBufferStart),
396 count);
397
398 if (fBufferEnd < endPosition)
399 fBufferEnd = endPosition;
400
401 }
402
403 // Else we need to write to the file.
404
405 else
406 {
407
408 // Write existing buffer.
409
410 Flush ();
411
412 // Write large blocks unbuffered.
413
414 if (count >= fBufferSize)
415 {
416
417 dng_abort_sniffer::SniffForAbort (fSniffer);
418
419 DoWrite (data, count, fPosition);
420
421 }
422
423 // Start a new buffer with small blocks.
424
425 else
426 {
427
428 fBufferDirty = true;
429
430 fBufferStart = fPosition;
431 fBufferEnd = endPosition;
432 fBufferLimit = fBufferStart + fBufferSize;
433
434 DoCopyBytes (data,
435 fBuffer,
436 count);
437
438 }
439
440 }
441
442 fPosition = endPosition;
443
444 fLength = Max_uint64 (Length (), fPosition);
445
446 }
447
448 /*****************************************************************************/
449
Get_uint16()450 uint16 dng_stream::Get_uint16 ()
451 {
452
453 uint16 x;
454
455 Get (&x, 2);
456
457 if (fSwapBytes)
458 {
459
460 x = SwapBytes16 (x);
461
462 }
463
464 return x;
465
466 }
467
468 /*****************************************************************************/
469
Put_uint16(uint16 x)470 void dng_stream::Put_uint16 (uint16 x)
471 {
472
473 if (fSwapBytes)
474 {
475
476 x = SwapBytes16 (x);
477
478 }
479
480 Put (&x, 2);
481
482 }
483
484 /*****************************************************************************/
485
Get_uint32()486 uint32 dng_stream::Get_uint32 ()
487 {
488
489 uint32 x;
490
491 Get (&x, 4);
492
493 if (fSwapBytes)
494 {
495
496 x = SwapBytes32 (x);
497
498 }
499
500 return x;
501
502 }
503
504 /*****************************************************************************/
505
Put_uint32(uint32 x)506 void dng_stream::Put_uint32 (uint32 x)
507 {
508
509 if (fSwapBytes)
510 {
511
512 x = SwapBytes32 (x);
513
514 }
515
516 Put (&x, 4);
517
518 }
519
520 /*****************************************************************************/
521
Get_uint64()522 uint64 dng_stream::Get_uint64 ()
523 {
524
525 if (fSwapBytes)
526 {
527
528 union
529 {
530 uint32 u32 [2];
531 uint64 u64;
532 } u;
533
534 u.u32 [1] = Get_uint32 ();
535 u.u32 [0] = Get_uint32 ();
536
537 return u.u64;
538
539 }
540
541 uint64 x;
542
543 Get (&x, 8);
544
545 return x;
546
547 }
548
549 /*****************************************************************************/
550
Put_uint64(uint64 x)551 void dng_stream::Put_uint64 (uint64 x)
552 {
553
554 if (fSwapBytes)
555 {
556
557 union
558 {
559 uint32 u32 [2];
560 uint64 u64;
561 } u;
562
563 u.u64 = x;
564
565 Put_uint32 (u.u32 [1]);
566 Put_uint32 (u.u32 [0]);
567
568 }
569
570 else
571 {
572
573 Put (&x, 8);
574
575 }
576
577 }
578
579 /*****************************************************************************/
580
Get_real32()581 real32 dng_stream::Get_real32 ()
582 {
583
584 union
585 {
586 uint32 i;
587 real32 r;
588 } u;
589
590 u.i = Get_uint32 ();
591
592 return u.r;
593
594 }
595
596 /*****************************************************************************/
597
Put_real32(real32 x)598 void dng_stream::Put_real32 (real32 x)
599 {
600
601 if (fSwapBytes)
602 {
603
604 union
605 {
606 uint32 i;
607 real32 r;
608 } u;
609
610 u.r = x;
611
612 Put_uint32 (u.i);
613
614 }
615
616 else
617 {
618
619 Put (&x, 4);
620
621 }
622
623 }
624
625 /*****************************************************************************/
626
Get_real64()627 real64 dng_stream::Get_real64 ()
628 {
629
630 if (fSwapBytes)
631 {
632
633 union
634 {
635 uint32 i [2];
636 real64 r;
637 } u;
638
639 u.i [1] = Get_uint32 ();
640 u.i [0] = Get_uint32 ();
641
642 return u.r;
643
644 }
645
646 real64 x;
647
648 Get (&x, 8);
649
650 return x;
651
652 }
653
654 /*****************************************************************************/
655
Put_real64(real64 x)656 void dng_stream::Put_real64 (real64 x)
657 {
658
659 if (fSwapBytes)
660 {
661
662 union
663 {
664 uint32 i [2];
665 real64 r;
666 } u;
667
668 u.r = x;
669
670 Put_uint32 (u.i [1]);
671 Put_uint32 (u.i [0]);
672
673 }
674
675 else
676 {
677
678 Put (&x, 8);
679
680 }
681
682 }
683
684 /*****************************************************************************/
685
Get_CString(char * data,uint32 maxLength)686 void dng_stream::Get_CString (char *data, uint32 maxLength)
687 {
688
689 memset (data, 0, maxLength);
690
691 uint32 index = 0;
692
693 while (true)
694 {
695
696 char c = (char) Get_uint8 ();
697
698 if (index + 1 < maxLength)
699 data [index++] = c;
700
701 if (c == 0)
702 break;
703
704 }
705
706 }
707
708 /*****************************************************************************/
709
Get_UString(char * data,uint32 maxLength)710 void dng_stream::Get_UString (char *data, uint32 maxLength)
711 {
712
713 memset (data, 0, maxLength);
714
715 uint32 index = 0;
716
717 while (true)
718 {
719
720 char c = (char) Get_uint16 ();
721
722 if (index + 1 < maxLength)
723 data [index++] = (char) c;
724
725 if (c == 0)
726 break;
727
728 }
729
730 }
731
732 /*****************************************************************************/
733
PutZeros(uint64 count)734 void dng_stream::PutZeros (uint64 count)
735 {
736
737 const uint32 kZeroBufferSize = 4096;
738
739 if (count >= kZeroBufferSize)
740 {
741
742 dng_memory_data zeroBuffer (kZeroBufferSize);
743
744 DoZeroBytes (zeroBuffer.Buffer (),
745 kZeroBufferSize);
746
747 while (count)
748 {
749
750 uint64 blockSize = Min_uint64 (count, kZeroBufferSize);
751
752 Put (zeroBuffer.Buffer (), (uint32) blockSize);
753
754 count -= blockSize;
755
756 }
757
758 }
759
760 else
761 {
762
763 uint32 count32 = (uint32) count;
764
765 for (uint32 j = 0; j < count32; j++)
766 {
767
768 Put_uint8 (0);
769
770 }
771
772 }
773
774 }
775
776 /*****************************************************************************/
777
PadAlign2()778 void dng_stream::PadAlign2 ()
779 {
780
781 PutZeros (Position () & 1);
782
783 }
784
785 /*****************************************************************************/
786
PadAlign4()787 void dng_stream::PadAlign4 ()
788 {
789
790 PutZeros ((4 - (Position () & 3)) & 3);
791
792 }
793
794 /*****************************************************************************/
795
TagValue_uint32(uint32 tagType)796 uint32 dng_stream::TagValue_uint32 (uint32 tagType)
797 {
798
799 switch (tagType)
800 {
801
802 case ttByte:
803 return (uint32) Get_uint8 ();
804
805 case ttShort:
806 return (uint32) Get_uint16 ();
807
808 case ttLong:
809 case ttIFD:
810 return Get_uint32 ();
811
812 }
813
814 real64 x = TagValue_real64 (tagType);
815
816 if (x < 0.0)
817 x = 0.0;
818
819 if (x > (real64) 0xFFFFFFFF)
820 x = (real64) 0xFFFFFFFF;
821
822 return ConvertDoubleToUint32(x + 0.5);
823
824 }
825
826 /*****************************************************************************/
827
TagValue_int32(uint32 tagType)828 int32 dng_stream::TagValue_int32 (uint32 tagType)
829 {
830
831 switch (tagType)
832 {
833
834 case ttSByte:
835 return (int32) Get_int8 ();
836
837 case ttSShort:
838 return (int32) Get_int16 ();
839
840 case ttSLong:
841 return Get_int32 ();
842
843 }
844
845 real64 x = TagValue_real64 (tagType);
846
847 if (x < 0.0)
848 {
849
850 if (x < -2147483648.0)
851 x = -2147483648.0;
852
853 return ConvertDoubleToInt32(x - 0.5);
854
855 }
856
857 else
858 {
859
860 if (x > 2147483647.0)
861 x = 2147483647.0;
862
863 return ConvertDoubleToInt32(x + 0.5);
864
865 }
866
867 }
868
869 /*****************************************************************************/
870
TagValue_urational(uint32 tagType)871 dng_urational dng_stream::TagValue_urational (uint32 tagType)
872 {
873
874 dng_urational result;
875
876 result.n = 0;
877 result.d = 1;
878
879 switch (tagType)
880 {
881
882 case ttRational:
883 {
884
885 result.n = Get_uint32 ();
886 result.d = Get_uint32 ();
887
888 break;
889
890 }
891
892 case ttSRational:
893 {
894
895 int32 n = Get_int32 ();
896 int32 d = Get_int32 ();
897
898 if ((n < 0) == (d < 0))
899 {
900
901 if (d < 0)
902 {
903 result.n = (uint32) ((int64) n * -1);
904 result.d = (uint32) ((int64) d * -1);
905 }
906 else
907 {
908 result.n = (uint32) n;
909 result.d = (uint32) d;
910 }
911
912 }
913
914 break;
915
916 }
917
918 case ttByte:
919 case ttShort:
920 case ttLong:
921 case ttIFD:
922 {
923
924 result.n = TagValue_uint32 (tagType);
925
926 break;
927
928 }
929
930 case ttSByte:
931 case ttSShort:
932 case ttSLong:
933 {
934
935 int32 n = TagValue_int32 (tagType);
936
937 if (n > 0)
938 {
939 result.n = (uint32) n;
940 }
941
942 break;
943
944 }
945
946 default:
947 {
948
949 real64 x = TagValue_real64 (tagType);
950
951 if (x > 0.0)
952 {
953
954 while (result.d < 10000 && x < 1000000)
955 {
956
957 result.d *= 10;
958
959 x *= 10.0;
960
961 }
962
963 result.n = ConvertDoubleToUint32(x + 0.5);
964
965 }
966
967 }
968
969 }
970
971 return result;
972
973 }
974
975 /*****************************************************************************/
976
TagValue_srational(uint32 tagType)977 dng_srational dng_stream::TagValue_srational (uint32 tagType)
978 {
979
980 dng_srational result;
981
982 result.n = 0;
983 result.d = 1;
984
985 switch (tagType)
986 {
987
988 case ttSRational:
989 {
990
991 result.n = Get_int32 ();
992 result.d = Get_int32 ();
993
994 break;
995
996 }
997
998 default:
999 {
1000
1001 real64 x = TagValue_real64 (tagType);
1002
1003 if (x > 0.0)
1004 {
1005
1006 while (result.d < 10000 && x < 1000000.0)
1007 {
1008
1009 result.d *= 10;
1010
1011 x *= 10.0;
1012
1013 }
1014
1015 result.n = ConvertDoubleToInt32(x + 0.5);
1016
1017 }
1018
1019 else
1020 {
1021
1022 while (result.d < 10000 && x > -1000000.0)
1023 {
1024
1025 result.d *= 10;
1026
1027 x *= 10.0;
1028
1029 }
1030
1031 result.n = ConvertDoubleToInt32(x - 0.5);
1032
1033 }
1034
1035 }
1036
1037 }
1038
1039 return result;
1040
1041 }
1042
1043 /*****************************************************************************/
1044
TagValue_real64(uint32 tagType)1045 real64 dng_stream::TagValue_real64 (uint32 tagType)
1046 {
1047
1048 switch (tagType)
1049 {
1050
1051 case ttByte:
1052 case ttShort:
1053 case ttLong:
1054 case ttIFD:
1055 return (real64) TagValue_uint32 (tagType);
1056
1057 case ttSByte:
1058 case ttSShort:
1059 case ttSLong:
1060 return (real64) TagValue_int32 (tagType);
1061
1062 case ttRational:
1063 {
1064
1065 uint32 n = Get_uint32 ();
1066 uint32 d = Get_uint32 ();
1067
1068 if (d == 0)
1069 return 0.0;
1070 else
1071 return (real64) n / (real64) d;
1072
1073 }
1074
1075 case ttSRational:
1076 {
1077
1078 int32 n = Get_int32 ();
1079 int32 d = Get_int32 ();
1080
1081 if (d == 0)
1082 return 0.0;
1083 else
1084 return (real64) n / (real64) d;
1085
1086 }
1087
1088 case ttFloat:
1089 return (real64) Get_real32 ();
1090
1091 case ttDouble:
1092 return Get_real64 ();
1093
1094 }
1095
1096 return 0.0;
1097
1098 }
1099
1100 /*****************************************************************************/
1101
CopyToStream(dng_stream & dstStream,uint64 count)1102 void dng_stream::CopyToStream (dng_stream &dstStream,
1103 uint64 count)
1104 {
1105
1106 uint8 smallBuffer [1024];
1107
1108 if (count <= sizeof (smallBuffer))
1109 {
1110
1111 Get (smallBuffer, (uint32) count);
1112
1113 dstStream.Put (smallBuffer, (uint32) count);
1114
1115 }
1116
1117 else
1118 {
1119
1120 const uint32 bigBufferSize = (uint32) Min_uint64 (kBigBufferSize,
1121 count);
1122
1123 dng_memory_data bigBuffer (bigBufferSize);
1124
1125 while (count)
1126 {
1127
1128 uint32 blockCount = (uint32) Min_uint64 (bigBufferSize,
1129 count);
1130
1131 Get (bigBuffer.Buffer (),
1132 blockCount);
1133
1134 dstStream.Put (bigBuffer.Buffer (),
1135 blockCount);
1136
1137 count -= blockCount;
1138
1139 }
1140
1141 }
1142
1143 }
1144
1145 /*****************************************************************************/
1146
DuplicateStream(dng_stream & dstStream)1147 void dng_stream::DuplicateStream (dng_stream &dstStream)
1148 {
1149
1150 // Turn off sniffers for this operation.
1151
1152 TempStreamSniffer noSniffer1 (*this , NULL);
1153 TempStreamSniffer noSniffer2 (dstStream, NULL);
1154
1155 // First grow the destination stream if required, in an attempt to
1156 // reserve any needed space before overwriting the existing data.
1157
1158 if (dstStream.Length () < Length ())
1159 {
1160 dstStream.SetLength (Length ());
1161 }
1162
1163 SetReadPosition (0);
1164
1165 dstStream.SetWritePosition (0);
1166
1167 CopyToStream (dstStream, Length ());
1168
1169 dstStream.Flush ();
1170
1171 dstStream.SetLength (Length ());
1172
1173 }
1174
1175 /*****************************************************************************/
1176
TempBigEndian(dng_stream & stream,bool bigEndian)1177 TempBigEndian::TempBigEndian (dng_stream &stream,
1178 bool bigEndian)
1179
1180 : fStream (stream)
1181 , fOldSwap (stream.SwapBytes ())
1182
1183 {
1184
1185 fStream.SetBigEndian (bigEndian);
1186
1187 }
1188
1189 /*****************************************************************************/
1190
~TempBigEndian()1191 TempBigEndian::~TempBigEndian ()
1192 {
1193
1194 fStream.SetSwapBytes (fOldSwap);
1195
1196 }
1197
1198 /*****************************************************************************/
1199
TempStreamSniffer(dng_stream & stream,dng_abort_sniffer * sniffer)1200 TempStreamSniffer::TempStreamSniffer (dng_stream &stream,
1201 dng_abort_sniffer *sniffer)
1202
1203 : fStream (stream)
1204 , fOldSniffer (stream.Sniffer ())
1205
1206 {
1207
1208 fStream.SetSniffer (sniffer);
1209
1210 }
1211
1212 /*****************************************************************************/
1213
~TempStreamSniffer()1214 TempStreamSniffer::~TempStreamSniffer ()
1215 {
1216
1217 fStream.SetSniffer (fOldSniffer);
1218
1219 }
1220
1221 /*****************************************************************************/
1222