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