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_memory_stream.cpp#1 $ */
10 /* $DateTime: 2012/05/30 13:28:51 $ */
11 /* $Change: 832332 $ */
12 /* $Author: tknoll $ */
13 
14 /*****************************************************************************/
15 
16 #include "dng_memory_stream.h"
17 
18 #include "dng_bottlenecks.h"
19 #include "dng_exceptions.h"
20 #include "dng_safe_arithmetic.h"
21 #include "dng_utils.h"
22 
23 /*****************************************************************************/
24 
dng_memory_stream(dng_memory_allocator & allocator,dng_abort_sniffer * sniffer,uint32 pageSize)25 dng_memory_stream::dng_memory_stream (dng_memory_allocator &allocator,
26 									  dng_abort_sniffer *sniffer,
27 						   			  uint32 pageSize)
28 
29 	:	dng_stream (sniffer,
30 					kDefaultBufferSize,
31 					kDNGStreamInvalidOffset)
32 
33 	,	fAllocator (allocator)
34 	,	fPageSize  (pageSize )
35 
36 	,	fPageCount      (0)
37 	,	fPagesAllocated (0)
38 	,	fPageList       (NULL)
39 
40 	,	fMemoryStreamLength (0)
41 
42 	{
43 
44 	}
45 
46 /*****************************************************************************/
47 
~dng_memory_stream()48 dng_memory_stream::~dng_memory_stream ()
49 	{
50 
51 	if (fPageList)
52 		{
53 
54 		for (uint32 index = 0; index < fPageCount; index++)
55 			{
56 
57 			delete fPageList [index];
58 
59 			}
60 
61 		free (fPageList);
62 
63 		}
64 
65 	}
66 
67 /*****************************************************************************/
68 
DoGetLength()69 uint64 dng_memory_stream::DoGetLength ()
70 	{
71 
72 	return fMemoryStreamLength;
73 
74 	}
75 
76 /*****************************************************************************/
77 
DoRead(void * data,uint32 count,uint64 offset)78 void dng_memory_stream::DoRead (void *data,
79 							    uint32 count,
80 							    uint64 offset)
81 	{
82 
83 	if (offset + count > fMemoryStreamLength)
84 		{
85 
86 		ThrowEndOfFile ();
87 
88 		}
89 
90 	uint64 baseOffset = offset;
91 
92 	while (count)
93 		{
94 
95 		uint32 pageIndex  = (uint32) (offset / fPageSize);
96 		uint32 pageOffset = (uint32) (offset % fPageSize);
97 
98 		uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count);
99 
100 		const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () +
101 						    pageOffset;
102 
103 		uint8 *dPtr = ((uint8 *) data) + (uint32) (offset - baseOffset);
104 
105 		DoCopyBytes (sPtr, dPtr, blockCount);
106 
107 		offset += blockCount;
108 		count  -= blockCount;
109 
110 		}
111 
112 	}
113 
114 /*****************************************************************************/
115 
DoSetLength(uint64 length)116 void dng_memory_stream::DoSetLength (uint64 length)
117 	{
118 
119 	while (length > fPageCount * (uint64) fPageSize)
120 		{
121 
122 		if (fPageCount == fPagesAllocated)
123 			{
124 
125 			uint32 newSizeTemp1 = 0, newSizeTemp2 = 0;
126 			if (!SafeUint32Add (fPagesAllocated, 32u, &newSizeTemp1) ||
127 				!SafeUint32Mult (fPagesAllocated, 2u, &newSizeTemp2))
128 				{
129 				ThrowMemoryFull ("Arithmetic overflow in DoSetLength()");
130 				}
131 			uint32 newSize = Max_uint32 (newSizeTemp1, newSizeTemp2);
132 			uint32 numBytes;
133 			if (!SafeUint32Mult (newSize, sizeof (dng_memory_block *),
134 								 &numBytes))
135 				{
136 				ThrowMemoryFull ("Arithmetic overflow in DoSetLength()");
137 				}
138 
139 			dng_memory_block **list = (dng_memory_block **) malloc (numBytes);
140 
141 			if (!list)
142 				{
143 
144 				ThrowMemoryFull ();
145 
146 				}
147 
148 			if (fPageCount)
149 				{
150 
151 				// The multiplication here is safe against overflow. fPageCount
152 				// can never reach a value that is large enough to cause
153 				// overflow because the computation of numBytes above would fail
154 				// before a list of that size could be allocated.
155 				DoCopyBytes (fPageList,
156 							 list,
157 							 fPageCount * (uint32) sizeof (dng_memory_block *));
158 
159 				}
160 
161 			if (fPageList)
162 				{
163 
164 				free (fPageList);
165 
166 				}
167 
168 			fPageList = list;
169 
170 			fPagesAllocated = newSize;
171 
172 			}
173 
174 		fPageList [fPageCount] = fAllocator.Allocate (fPageSize);
175 
176 		fPageCount++;
177 
178 		}
179 
180 	fMemoryStreamLength = length;
181 
182 	}
183 
184 /*****************************************************************************/
185 
DoWrite(const void * data,uint32 count,uint64 offset)186 void dng_memory_stream::DoWrite (const void *data,
187 							     uint32 count,
188 							     uint64 offset)
189 	{
190 
191 	DoSetLength (Max_uint64 (fMemoryStreamLength,
192 							 offset + count));
193 
194 	uint64 baseOffset = offset;
195 
196 	while (count)
197 		{
198 
199 		uint32 pageIndex  = (uint32) (offset / fPageSize);
200 		uint32 pageOffset = (uint32) (offset % fPageSize);
201 
202 		uint32 blockCount = Min_uint32 (fPageSize - pageOffset, count);
203 
204 		const uint8 *sPtr = ((const uint8 *) data) + (uint32) (offset - baseOffset);
205 
206 		uint8 *dPtr = fPageList [pageIndex]->Buffer_uint8 () +
207 					  pageOffset;
208 
209 		DoCopyBytes (sPtr, dPtr, blockCount);
210 
211 		offset += blockCount;
212 		count  -= blockCount;
213 
214 		}
215 
216 	}
217 
218 /*****************************************************************************/
219 
CopyToStream(dng_stream & dstStream,uint64 count)220 void dng_memory_stream::CopyToStream (dng_stream &dstStream,
221 									  uint64 count)
222 	{
223 
224 	if (count < kBigBufferSize)
225 		{
226 
227 		dng_stream::CopyToStream (dstStream, count);
228 
229 		}
230 
231 	else
232 		{
233 
234 		Flush ();
235 
236 		uint64 offset = Position ();
237 
238 		if (offset + count > Length ())
239 			{
240 
241 			ThrowEndOfFile ();
242 
243 			}
244 
245 		while (count)
246 			{
247 
248 			uint32 pageIndex  = (uint32) (offset / fPageSize);
249 			uint32 pageOffset = (uint32) (offset % fPageSize);
250 
251 			uint32 blockCount = (uint32) Min_uint64 (fPageSize - pageOffset, count);
252 
253 			const uint8 *sPtr = fPageList [pageIndex]->Buffer_uint8 () +
254 								pageOffset;
255 
256 			dstStream.Put (sPtr, blockCount);
257 
258 			offset += blockCount;
259 			count  -= blockCount;
260 
261 			}
262 
263 		SetReadPosition (offset);
264 
265 		}
266 
267 	}
268 
269 /*****************************************************************************/
270