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
25dng_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
48dng_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
69uint64 dng_memory_stream::DoGetLength ()
70 {
71
72 return fMemoryStreamLength;
73
74 }
75
76/*****************************************************************************/
77
78void 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
116void 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
186void 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
220void 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