1 /*****************************************************************
2 |
3 |   Platinum - Ring Buffer Stream
4 |
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
6 | All rights reserved.
7 | http://www.plutinosoft.com
8 |
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
13 |
14 | OEMs, ISVs, VARs and other distributors that combine and
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20 | licensing@plutinosoft.com
21 |
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25 | GNU General Public License for more details.
26 |
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
32 |
33 ****************************************************************/
34 
35 /*----------------------------------------------------------------------
36 |   includes
37 +---------------------------------------------------------------------*/
38 #include "PltRingBufferStream.h"
39 #include "Neptune.h"
40 
41 /*----------------------------------------------------------------------
42 |   defines
43 +---------------------------------------------------------------------*/
44 #ifdef max
45 #undef max
46 #endif
47 #define max(a,b)    (((a) > (b)) ? (a) : (b))
48 
49 #ifdef min
50 #undef min
51 #endif
52 #define min(a,b)    (((a) < (b)) ? (a) : (b))
53 
54 /*----------------------------------------------------------------------
55 |   PLT_RingBufferStream::PLT_RingBufferStream
56 +---------------------------------------------------------------------*/
PLT_RingBufferStream(NPT_Size buffer_size,bool blocking)57 PLT_RingBufferStream::PLT_RingBufferStream(NPT_Size buffer_size,
58                                            bool     blocking /* = true */) :
59     m_TotalBytesRead(0),
60     m_TotalBytesWritten(0),
61     m_Blocking(blocking),
62     m_Eos(false),
63     m_Aborted(false)
64 {
65     m_RingBuffer = new NPT_RingBuffer(buffer_size);
66 }
67 
68 /*----------------------------------------------------------------------
69 |   PLT_RingBufferStream::PLT_RingBufferStream
70 +---------------------------------------------------------------------*/
PLT_RingBufferStream(NPT_RingBufferReference & buffer,bool blocking)71 PLT_RingBufferStream::PLT_RingBufferStream(NPT_RingBufferReference& buffer,
72                                            bool blocking /* = true */) :
73     m_RingBuffer(buffer),
74     m_TotalBytesRead(0),
75     m_TotalBytesWritten(0),
76     m_Blocking(blocking),
77     m_Eos(false),
78     m_Aborted(false)
79 {
80 }
81 
82 /*----------------------------------------------------------------------
83 |   PLT_RingBufferStream::~PLT_RingBufferStream
84 +---------------------------------------------------------------------*/
~PLT_RingBufferStream()85 PLT_RingBufferStream::~PLT_RingBufferStream()
86 {
87 }
88 
89 /*----------------------------------------------------------------------
90 |   PLT_RingBufferStream::Read
91 +---------------------------------------------------------------------*/
92 NPT_Result
Read(void * buffer,NPT_Size max_bytes_to_read,NPT_Size * _bytes_read)93 PLT_RingBufferStream::Read(void*     buffer,
94                            NPT_Size  max_bytes_to_read,
95                            NPT_Size* _bytes_read /*= NULL*/)
96 {
97     NPT_Size bytes_to_read;
98     NPT_Size bytes_read = 0;
99 
100     // reset output param first
101     if (_bytes_read) *_bytes_read = 0;
102 
103     // wait for data
104     do {
105         {
106             NPT_AutoLock autoLock(m_Lock);
107 
108             if (m_Aborted) {
109                 return NPT_ERROR_INTERRUPTED;
110             }
111 
112             // check for data
113             if (m_RingBuffer->GetAvailable())
114                 break;
115 
116             if (m_Eos) {
117                 return NPT_ERROR_EOS;
118             } else if (!m_Blocking) {
119                 return NPT_ERROR_WOULD_BLOCK;
120             }
121         }
122 
123         // sleep and try again
124         NPT_System::Sleep(NPT_TimeInterval(.1));
125     } while (1);
126 
127     {
128         NPT_AutoLock autoLock(m_Lock);
129 
130         // try twice in case available data was not contiguous
131         for (int i=0; i<2; i++) {
132             bytes_to_read = min(max_bytes_to_read - bytes_read, m_RingBuffer->GetContiguousAvailable());
133 
134             // break if nothing to read the second time
135             if (bytes_to_read == 0) break;
136 
137             // read into buffer and advance
138             NPT_CHECK(m_RingBuffer->Read((unsigned char*)buffer+bytes_read, bytes_to_read));
139 
140             // keep track of the total bytes we have read so far
141             m_TotalBytesRead += bytes_to_read;
142             bytes_read += bytes_to_read;
143 
144             if (_bytes_read) *_bytes_read += bytes_to_read;
145         }
146     }
147 
148     // we have read some chars, so return success
149     // even if we have read less than asked
150     return NPT_SUCCESS;
151 }
152 
153 /*----------------------------------------------------------------------
154 |   PLT_RingBufferStream::Write
155 +---------------------------------------------------------------------*/
156 NPT_Result
Write(const void * buffer,NPT_Size max_bytes_to_write,NPT_Size * _bytes_written)157 PLT_RingBufferStream::Write(const void* buffer,
158                             NPT_Size    max_bytes_to_write,
159                             NPT_Size*   _bytes_written /*= NULL*/)
160 {
161     NPT_Size bytes_to_write;
162     NPT_Size bytes_written = 0;
163 
164     // reset output param first
165     if (_bytes_written) *_bytes_written = 0;
166 
167     // wait for space
168     do {
169         {
170             NPT_AutoLock autoLock(m_Lock);
171 
172             if (m_Aborted) {
173                 return NPT_ERROR_INTERRUPTED;
174             }
175 
176             // return immediately if we are told we're finished
177             if (m_Eos) {
178                 return NPT_ERROR_EOS;
179             }
180 
181             if (m_RingBuffer->GetSpace())
182                 break;
183 
184             if (!m_Blocking) {
185                 return NPT_ERROR_WOULD_BLOCK;
186             }
187         }
188 
189         // sleep and try again
190         NPT_System::Sleep(NPT_TimeInterval(.1));
191     } while (1);
192 
193     {
194         NPT_AutoLock autoLock(m_Lock);
195 
196         // try twice in case available space was not contiguous
197         for (int i=0; i<2; i++) {
198             bytes_to_write = min(max_bytes_to_write - bytes_written, m_RingBuffer->GetContiguousSpace());
199 
200             // break if no space to write the second time
201             if (bytes_to_write == 0) break;
202 
203             // write into buffer
204             NPT_CHECK(m_RingBuffer->Write((unsigned char*)buffer+bytes_written, bytes_to_write));
205 
206             m_TotalBytesWritten += bytes_to_write;
207             bytes_written += bytes_to_write;
208 
209             if (_bytes_written) *_bytes_written += bytes_to_write;
210         }
211     }
212 
213     // we have written some chars, so return success
214     // even if we have written less than provided
215     return NPT_SUCCESS;
216 }
217 
218 /*----------------------------------------------------------------------
219 |   PLT_RingBufferStream::Flush
220 +---------------------------------------------------------------------*/
221 NPT_Result
Flush()222 PLT_RingBufferStream::Flush()
223 {
224     NPT_AutoLock autoLock(m_Lock);
225 
226     m_RingBuffer->Flush();
227     m_TotalBytesRead = 0;
228     m_TotalBytesWritten = 0;
229     return NPT_SUCCESS;
230 }
231 
232 /*----------------------------------------------------------------------
233 |   PLT_RingBufferStream::SetEOS
234 +---------------------------------------------------------------------*/
235 NPT_Result
SetEOS()236 PLT_RingBufferStream::SetEOS()
237 {
238     NPT_AutoLock autoLock(m_Lock);
239 
240     m_Eos = true;
241     return NPT_SUCCESS;
242 }
243 
244 
245 /*----------------------------------------------------------------------
246  |   PLT_RingBufferStream::Abort
247  +---------------------------------------------------------------------*/
248 NPT_Result
Abort()249 PLT_RingBufferStream::Abort()
250 {
251     NPT_AutoLock autoLock(m_Lock);
252 
253     m_Aborted = true;
254     return NPT_SUCCESS;
255 }
256