Line data Source code
1 : /* Copyright (C) 2010 Wildfire Games.
2 : *
3 : * Permission is hereby granted, free of charge, to any person obtaining
4 : * a copy of this software and associated documentation files (the
5 : * "Software"), to deal in the Software without restriction, including
6 : * without limitation the rights to use, copy, modify, merge, publish,
7 : * distribute, sublicense, and/or sell copies of the Software, and to
8 : * permit persons to whom the Software is furnished to do so, subject to
9 : * the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included
12 : * in all copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 : * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 : * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 : * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 : * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 : */
22 :
23 : #include "precompiled.h"
24 : #include "lib/file/archive/stream.h"
25 :
26 : #include "lib/allocators/page_aligned.h"
27 : #include "lib/allocators/shared_ptr.h"
28 : #include "lib/file/archive/codec.h"
29 : //#include "lib/timer.h"
30 :
31 : //TIMER_ADD_CLIENT(tc_stream);
32 :
33 :
34 0 : OutputBufferManager::OutputBufferManager()
35 : {
36 0 : Reset();
37 0 : }
38 :
39 0 : void OutputBufferManager::Reset()
40 : {
41 0 : m_buffer = 0;
42 0 : m_size = 0;
43 0 : m_capacity = 0;
44 0 : }
45 :
46 0 : void OutputBufferManager::SetBuffer(u8* buffer, size_t size)
47 : {
48 0 : ENSURE(IsAllowableBuffer(buffer, size));
49 :
50 0 : m_buffer = buffer;
51 0 : m_size = size;
52 0 : }
53 :
54 0 : void OutputBufferManager::AllocateBuffer(size_t size)
55 : {
56 : // notes:
57 : // - this implementation allows reusing previous buffers if they
58 : // are big enough, which reduces the number of allocations.
59 : // - no further attempts to reduce allocations (e.g. by doubling
60 : // the current size) are made; this strategy is enough.
61 : // - Pool etc. cannot be used because files may be huge (larger
62 : // than the address space of 32-bit systems).
63 :
64 : // no buffer or the previous one wasn't big enough: reallocate
65 0 : if(!m_mem || m_capacity < size)
66 : {
67 0 : AllocateAligned(m_mem, size);
68 0 : m_capacity = size;
69 : }
70 :
71 0 : SetBuffer(m_mem.get(), size);
72 0 : }
73 :
74 0 : bool OutputBufferManager::IsAllowableBuffer(u8* buffer, size_t size)
75 : {
76 : // none yet established
77 0 : if(m_buffer == 0 && m_size == 0)
78 0 : return true;
79 :
80 : // same as last time (happens with temp buffers)
81 0 : if(m_buffer == buffer && m_size == size)
82 0 : return true;
83 :
84 : // located after the last buffer (note: not necessarily after
85 : // the entire buffer; a lack of input can cause the output buffer
86 : // to only partially be used before the next call.)
87 0 : if((unsigned)(buffer - m_buffer) <= m_size)
88 0 : return true;
89 :
90 0 : return false;
91 : }
92 :
93 :
94 : //-----------------------------------------------------------------------------
95 :
96 :
97 0 : Stream::Stream(const PICodec& codec)
98 : : m_codec(codec)
99 0 : , m_inConsumed(0), m_outProduced(0)
100 : {
101 0 : }
102 :
103 :
104 0 : void Stream::AllocateOutputBuffer(size_t outSizeMax)
105 : {
106 0 : m_outputBufferManager.AllocateBuffer(outSizeMax);
107 0 : }
108 :
109 :
110 0 : void Stream::SetOutputBuffer(u8* out, size_t outSize)
111 : {
112 0 : m_outputBufferManager.SetBuffer(out, outSize);
113 0 : }
114 :
115 :
116 0 : Status Stream::Feed(const u8* in, size_t inSize)
117 : {
118 0 : if(m_outProduced == m_outputBufferManager.Size()) // output buffer full; must not call Process
119 0 : return INFO::ALL_COMPLETE;
120 :
121 : size_t inConsumed, outProduced;
122 0 : u8* const out = m_outputBufferManager.Buffer() + m_outProduced;
123 0 : const size_t outSize = m_outputBufferManager.Size() - m_outProduced;
124 0 : RETURN_STATUS_IF_ERR(m_codec->Process(in, inSize, out, outSize, inConsumed, outProduced));
125 :
126 0 : m_inConsumed += inConsumed;
127 0 : m_outProduced += outProduced;
128 0 : return INFO::OK;
129 : }
130 :
131 :
132 0 : Status Stream::Finish()
133 : {
134 : size_t outProduced;
135 0 : RETURN_STATUS_IF_ERR(m_codec->Finish(m_checksum, outProduced));
136 0 : m_outProduced += outProduced;
137 0 : return INFO::OK;
138 3 : }
|