This change is for fixing the potential integer overflow from "offset + size"
[pdfium.git] / core / src / fxcrt / extension.h
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #ifndef _FXCRT_EXTENSION_IMP_
8 #define _FXCRT_EXTENSION_IMP_
9
10 #include "../../../third_party/numerics/safe_math.h"
11
12 class IFXCRT_FileAccess
13 {
14 public:
15     virtual ~IFXCRT_FileAccess() {}
16     virtual FX_BOOL             Open(FX_BSTR fileName, FX_DWORD dwMode) = 0;
17     virtual FX_BOOL             Open(FX_WSTR fileName, FX_DWORD dwMode) = 0;
18     virtual void                Close() = 0;
19     virtual void                Release() = 0;
20     virtual FX_FILESIZE GetSize() const = 0;
21     virtual FX_FILESIZE GetPosition() const = 0;
22     virtual FX_FILESIZE SetPosition(FX_FILESIZE pos) = 0;
23     virtual size_t              Read(void* pBuffer, size_t szBuffer) = 0;
24     virtual size_t              Write(const void* pBuffer, size_t szBuffer) = 0;
25     virtual size_t              ReadPos(void* pBuffer, size_t szBuffer, FX_FILESIZE pos) = 0;
26     virtual size_t              WritePos(const void* pBuffer, size_t szBuffer, FX_FILESIZE pos) = 0;
27     virtual FX_BOOL             Flush() = 0;
28     virtual FX_BOOL             Truncate(FX_FILESIZE szFile) = 0;
29 };
30 IFXCRT_FileAccess*      FXCRT_FileAccess_Create();
31 class CFX_CRTFileStream FX_FINAL : public IFX_FileStream, public CFX_Object
32 {
33 public:
34     CFX_CRTFileStream(IFXCRT_FileAccess* pFA) : m_pFile(pFA), m_dwCount(1), m_bUseRange(FALSE), m_nOffset(0), m_nSize(0) {}
35     ~CFX_CRTFileStream()
36     {
37         if (m_pFile) {
38             m_pFile->Release();
39         }
40     }
41     virtual IFX_FileStream*             Retain()
42     {
43         m_dwCount ++;
44         return this;
45     }
46     virtual void                                Release()
47     {
48         FX_DWORD nCount = -- m_dwCount;
49         if (!nCount) {
50             delete this;
51         }
52     }
53     virtual FX_FILESIZE                 GetSize()
54     {
55         return m_bUseRange ? m_nSize : m_pFile->GetSize();
56     }
57     virtual FX_BOOL                             IsEOF()
58     {
59         return GetPosition() >= GetSize();
60     }
61     virtual FX_FILESIZE                 GetPosition()
62     {
63         FX_FILESIZE pos = m_pFile->GetPosition();
64         if (m_bUseRange) {
65             pos -= m_nOffset;
66         }
67         return pos;
68     }
69     virtual FX_BOOL                             SetRange(FX_FILESIZE offset, FX_FILESIZE size)
70     {
71         if (offset < 0 || offset + size > m_pFile->GetSize()) {
72             return FALSE;
73         }
74         m_nOffset = offset, m_nSize = size;
75         m_bUseRange = TRUE;
76         m_pFile->SetPosition(m_nOffset);
77         return TRUE;
78     }
79     virtual void                                ClearRange()
80     {
81         m_bUseRange = FALSE;
82     }
83     virtual FX_BOOL                             ReadBlock(void* buffer, FX_FILESIZE offset, size_t size)
84     {
85         if (m_bUseRange) {
86             if (offset + size > (size_t)GetSize()) {
87                 return FALSE;
88             }
89             offset += m_nOffset;
90         }
91         return (FX_BOOL)m_pFile->ReadPos(buffer, size, offset);
92     }
93     virtual size_t                              ReadBlock(void* buffer, size_t size)
94     {
95         if (m_bUseRange) {
96             FX_FILESIZE availSize = m_nOffset + m_nSize - m_pFile->GetPosition();
97             if ((size_t)availSize < size) {
98                 size -= size - (size_t)availSize;
99             }
100         }
101         return m_pFile->Read(buffer, size);
102     }
103     virtual     FX_BOOL                         WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size)
104     {
105         if (m_bUseRange) {
106             offset += m_nOffset;
107         }
108         return (FX_BOOL)m_pFile->WritePos(buffer, size, offset);
109     }
110     virtual FX_BOOL                             Flush()
111     {
112         return m_pFile->Flush();
113     }
114     IFXCRT_FileAccess*  m_pFile;
115     FX_DWORD                    m_dwCount;
116     FX_BOOL                             m_bUseRange;
117     FX_FILESIZE                 m_nOffset;
118     FX_FILESIZE                 m_nSize;
119 };
120 #define FX_MEMSTREAM_BlockSize          (64 * 1024)
121 #define FX_MEMSTREAM_Consecutive        0x01
122 #define FX_MEMSTREAM_TakeOver           0x02
123 class CFX_MemoryStream FX_FINAL : public IFX_MemoryStream, public CFX_Object
124 {
125 public:
126     CFX_MemoryStream(FX_BOOL bConsecutive)
127         : m_dwCount(1)
128         , m_nTotalSize(0)
129         , m_nCurSize(0)
130         , m_nCurPos(0)
131         , m_nGrowSize(FX_MEMSTREAM_BlockSize)
132         , m_bUseRange(FALSE)
133     {
134         m_dwFlags = FX_MEMSTREAM_TakeOver | (bConsecutive ? FX_MEMSTREAM_Consecutive : 0);
135     }
136     CFX_MemoryStream(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver)
137         : m_dwCount(1)
138         , m_nTotalSize(nSize)
139         , m_nCurSize(nSize)
140         , m_nCurPos(0)
141         , m_nGrowSize(FX_MEMSTREAM_BlockSize)
142         , m_bUseRange(FALSE)
143     {
144         m_Blocks.Add(pBuffer);
145         m_dwFlags = FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
146     }
147     ~CFX_MemoryStream()
148     {
149         if (m_dwFlags & FX_MEMSTREAM_TakeOver) {
150             for (FX_INT32 i = 0; i < m_Blocks.GetSize(); i++) {
151                 FX_Free((FX_LPBYTE)m_Blocks[i]);
152             }
153         }
154         m_Blocks.RemoveAll();
155     }
156     virtual IFX_FileStream*             Retain()
157     {
158         m_dwCount ++;
159         return this;
160     }
161     virtual void                                Release()
162     {
163         FX_DWORD nCount = -- m_dwCount;
164         if (nCount) {
165             return;
166         }
167         delete this;
168     }
169     virtual FX_FILESIZE                 GetSize()
170     {
171         return m_bUseRange ? (FX_FILESIZE) m_nSize : (FX_FILESIZE)m_nCurSize;
172     }
173     virtual FX_BOOL                             IsEOF()
174     {
175         return m_nCurPos >= (size_t)GetSize();
176     }
177     virtual FX_FILESIZE                 GetPosition()
178     {
179         FX_FILESIZE pos = (FX_FILESIZE)m_nCurPos;
180         if (m_bUseRange) {
181             pos -= (FX_FILESIZE)m_nOffset;
182         }
183         return pos;
184     }
185     virtual FX_BOOL                             SetRange(FX_FILESIZE offset, FX_FILESIZE size)
186     {
187         base::CheckedNumeric<FX_FILESIZE> range = size;
188         range += size;
189  
190         if (!range.IsValid() || offset <= 0 || size <= 0 || range.ValueOrDie() > m_nCurSize) {
191             return FALSE;
192         }
193         
194         m_nOffset = (size_t)offset, m_nSize = (size_t)size;
195         m_bUseRange = TRUE;
196         m_nCurPos = m_nOffset;
197         return TRUE;
198     }
199     virtual void                                ClearRange()
200     {
201         m_bUseRange = FALSE;
202     }
203     virtual FX_BOOL                             ReadBlock(void* buffer, FX_FILESIZE offset, size_t size)
204     {
205         if (!buffer || !size) {
206             return FALSE;
207         }
208
209         base::CheckedNumeric<FX_FILESIZE> safeOffset = offset;
210         if (m_bUseRange) {
211             safeOffset += m_nOffset;
212         }
213          
214         if (!safeOffset.IsValid()) {
215             return FALSE;
216         }
217
218         offset = safeOffset.ValueOrDie();
219
220         base::CheckedNumeric<size_t> newPos = size;
221         newPos += offset;
222         if (!newPos.IsValid() || newPos.ValueOrDefault(0) == 0 || newPos.ValueOrDie() > m_nCurSize) {
223             return FALSE;
224         }
225
226         m_nCurPos = newPos.ValueOrDie();
227         if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
228             FXSYS_memcpy32(buffer, (FX_LPBYTE)m_Blocks[0] + (size_t)offset, size);
229             return TRUE;
230         }
231         size_t nStartBlock = (size_t)offset / m_nGrowSize;
232         offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);
233         while (size) {
234             size_t nRead = m_nGrowSize - (size_t)offset;
235             if (nRead > size) {
236                 nRead = size;
237             }
238             FXSYS_memcpy32(buffer, (FX_LPBYTE)m_Blocks[(int)nStartBlock] + (size_t)offset, nRead);
239             buffer = ((FX_LPBYTE)buffer) + nRead;
240             size -= nRead;
241             nStartBlock ++;
242             offset = 0;
243         }
244         return TRUE;
245     }
246     virtual size_t                              ReadBlock(void* buffer, size_t size)
247     {
248         if (m_nCurPos >= m_nCurSize) {
249             return 0;
250         }
251         if (m_bUseRange) {
252             size_t availSize = m_nOffset + m_nSize - m_nCurPos;
253             if (availSize < size) {
254                 size -= size - (size_t)availSize;
255             }
256         }
257         size_t nRead = FX_MIN(size, m_nCurSize - m_nCurPos);
258         if (!ReadBlock(buffer, (FX_INT32)m_nCurPos, nRead)) {
259             return 0;
260         }
261         return nRead;
262     }
263     virtual     FX_BOOL                         WriteBlock(const void* buffer, FX_FILESIZE offset, size_t size)
264     {
265         if (!buffer || !size) {
266             return FALSE;
267         }
268         if (m_bUseRange) {
269             offset += (FX_FILESIZE)m_nOffset;
270         }
271         if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
272             base::CheckedNumeric<size_t> newPos = size; 
273             newPos += offset;
274             if (!newPos.IsValid())
275                 return FALSE;
276
277             m_nCurPos = newPos.ValueOrDie();
278             if (m_nCurPos > m_nTotalSize) {
279                 m_nTotalSize = (m_nCurPos + m_nGrowSize - 1) / m_nGrowSize * m_nGrowSize;
280                 if (m_Blocks.GetSize() < 1) {
281                     void* block = FX_Alloc(FX_BYTE, m_nTotalSize);
282                     m_Blocks.Add(block);
283                 } else {
284                     m_Blocks[0] = FX_Realloc(FX_BYTE, m_Blocks[0], m_nTotalSize);
285                 }
286                 if (!m_Blocks[0]) {
287                     m_Blocks.RemoveAll();
288                     return FALSE;
289                 }
290             }
291             FXSYS_memcpy32((FX_LPBYTE)m_Blocks[0] + (size_t)offset, buffer, size);
292             if (m_nCurSize < m_nCurPos) {
293                 m_nCurSize = m_nCurPos;
294             }
295             return TRUE;
296         }
297
298         base::CheckedNumeric<size_t> newPos = size;
299         newPos += offset;
300         if (!newPos.IsValid())
301             return FALSE;
302
303         if (!ExpandBlocks(newPos.ValueOrDie())) {
304             return FALSE;
305         }
306         m_nCurPos = newPos.ValueOrDie();
307         size_t nStartBlock = (size_t)offset / m_nGrowSize;
308         offset -= (FX_FILESIZE)(nStartBlock * m_nGrowSize);
309         while (size) {
310             size_t nWrite = m_nGrowSize - (size_t)offset;
311             if (nWrite > size) {
312                 nWrite = size;
313             }
314             FXSYS_memcpy32((FX_LPBYTE)m_Blocks[(int)nStartBlock] + (size_t)offset, buffer, nWrite);
315             buffer = ((FX_LPBYTE)buffer) + nWrite;
316             size -= nWrite;
317             nStartBlock ++;
318             offset = 0;
319         }
320         return TRUE;
321     }
322     virtual FX_BOOL                             Flush()
323     {
324         return TRUE;
325     }
326     virtual FX_BOOL                             IsConsecutive() const
327     {
328         return m_dwFlags & FX_MEMSTREAM_Consecutive;
329     }
330     virtual void                                EstimateSize(size_t nInitSize, size_t nGrowSize)
331     {
332         if (m_dwFlags & FX_MEMSTREAM_Consecutive) {
333             if (m_Blocks.GetSize() < 1) {
334                 FX_LPBYTE pBlock = FX_Alloc(FX_BYTE, FX_MAX(nInitSize, 4096));
335                 if (pBlock) {
336                     m_Blocks.Add(pBlock);
337                 }
338             }
339             m_nGrowSize = FX_MAX(nGrowSize, 4096);
340         } else if (m_Blocks.GetSize() < 1) {
341             m_nGrowSize = FX_MAX(nGrowSize, 4096);
342         }
343     }
344     virtual FX_LPBYTE                   GetBuffer() const
345     {
346         return m_Blocks.GetSize() ? (FX_LPBYTE)m_Blocks[0] : NULL;
347     }
348     virtual void                                AttachBuffer(FX_LPBYTE pBuffer, size_t nSize, FX_BOOL bTakeOver = FALSE)
349     {
350         if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {
351             return;
352         }
353         m_Blocks.RemoveAll();
354         m_Blocks.Add(pBuffer);
355         m_nTotalSize = m_nCurSize = nSize;
356         m_nCurPos = 0;
357         m_dwFlags = FX_MEMSTREAM_Consecutive | (bTakeOver ? FX_MEMSTREAM_TakeOver : 0);
358         ClearRange();
359     }
360     virtual void                                DetachBuffer()
361     {
362         if (!(m_dwFlags & FX_MEMSTREAM_Consecutive)) {
363             return;
364         }
365         m_Blocks.RemoveAll();
366         m_nTotalSize = m_nCurSize = m_nCurPos = 0;
367         m_dwFlags = FX_MEMSTREAM_TakeOver;
368         ClearRange();
369     }
370 protected:
371     CFX_PtrArray        m_Blocks;
372     FX_DWORD            m_dwCount;
373     size_t                      m_nTotalSize;
374     size_t                      m_nCurSize;
375     size_t                      m_nCurPos;
376     size_t                      m_nGrowSize;
377     FX_DWORD            m_dwFlags;
378     FX_BOOL                     m_bUseRange;
379     size_t                      m_nOffset;
380     size_t                      m_nSize;
381     FX_BOOL     ExpandBlocks(size_t size)
382     {
383         if (m_nCurSize < size) {
384             m_nCurSize = size;
385         }
386         if (size <= m_nTotalSize) {
387             return TRUE;
388         }
389         FX_INT32 iCount = m_Blocks.GetSize();
390         size = (size - m_nTotalSize + m_nGrowSize - 1) / m_nGrowSize;
391         m_Blocks.SetSize(m_Blocks.GetSize() + (FX_INT32)size);
392         while (size --) {
393             FX_LPBYTE pBlock = FX_Alloc(FX_BYTE, m_nGrowSize);
394             if (!pBlock) {
395                 return FALSE;
396             }
397             m_Blocks.SetAt(iCount ++, pBlock);
398             m_nTotalSize += m_nGrowSize;
399         }
400         return TRUE;
401     }
402 };
403 #ifdef __cplusplus
404 extern "C" {
405 #endif
406 #define MT_N                    848
407 #define MT_M                    456
408 #define MT_Matrix_A             0x9908b0df
409 #define MT_Upper_Mask   0x80000000
410 #define MT_Lower_Mask   0x7fffffff
411 typedef struct _FX_MTRANDOMCONTEXT {
412     _FX_MTRANDOMCONTEXT()
413     {
414         mti = MT_N + 1;
415         bHaveSeed = FALSE;
416     }
417     FX_DWORD mti;
418     FX_BOOL      bHaveSeed;
419     FX_DWORD mt[MT_N];
420 } FX_MTRANDOMCONTEXT, * FX_LPMTRANDOMCONTEXT;
421 typedef FX_MTRANDOMCONTEXT const * FX_LPCMTRANDOMCONTEXT;
422 #if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
423 FX_BOOL FX_GenerateCryptoRandom(FX_LPDWORD pBuffer, FX_INT32 iCount);
424 #endif
425 #ifdef __cplusplus
426 }
427 #endif
428 #endif