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