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