Merge pull request #4676 from jmarshallnz/dont_set_scraper_on_tvshow_on_nfo
[vuplus_xbmc] / xbmc / utils / RingBuffer.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "RingBuffer.h"
22 #include "threads/SingleLock.h"
23
24 #include <cstring>
25 #include <cstdlib>
26 #include <algorithm>
27
28 /* Constructor */
29 CRingBuffer::CRingBuffer()
30 {
31   m_buffer = NULL;
32   m_size = 0;
33   m_readPtr = 0;
34   m_writePtr = 0;
35   m_fillCount = 0;
36 }
37
38 /* Destructor */
39 CRingBuffer::~CRingBuffer()
40 {
41   Destroy();
42 }
43
44 /* Create a ring buffer with the specified 'size' */
45 bool CRingBuffer::Create(unsigned int size)
46 {
47   CSingleLock lock(m_critSection);
48   m_buffer = (char*)malloc(size);
49   if (m_buffer != NULL)
50   {
51     m_size = size;
52     return true;
53   }
54   return false;
55 }
56
57 /* Free the ring buffer and set all values to NULL or 0 */
58 void CRingBuffer::Destroy()
59 {
60   CSingleLock lock(m_critSection);
61   if (m_buffer != NULL)
62   {
63     free(m_buffer);
64     m_buffer = NULL;
65   }
66   m_size = 0;
67   m_readPtr = 0;
68   m_writePtr = 0;
69   m_fillCount = 0;
70 }
71
72 /* Clear the ring buffer */
73 void CRingBuffer::Clear()
74 {
75   CSingleLock lock(m_critSection);
76   m_readPtr = 0;
77   m_writePtr = 0;
78   m_fillCount = 0;
79 }
80
81 /* Read in data from the ring buffer to the supplied buffer 'buf'. The amount
82  * read in is specified by 'size'.
83  */
84 bool CRingBuffer::ReadData(char *buf, unsigned int size)
85 {
86   CSingleLock lock(m_critSection);
87   if (size > m_fillCount)
88   {
89     return false;
90   }
91   if (size + m_readPtr > m_size)
92   {
93     unsigned int chunk = m_size - m_readPtr;
94     memcpy(buf, m_buffer + m_readPtr, chunk);
95     memcpy(buf + chunk, m_buffer, size - chunk);
96     m_readPtr = size - chunk;
97   }
98   else
99   {
100     memcpy(buf, m_buffer + m_readPtr, size);
101     m_readPtr += size;
102   }
103   if (m_readPtr == m_size)
104     m_readPtr = 0;
105   m_fillCount -= size;
106   return true;
107 }
108
109 /* Read in data from the ring buffer to another ring buffer object specified by
110  * 'rBuf'.
111  */
112 bool CRingBuffer::ReadData(CRingBuffer &rBuf, unsigned int size)
113 {
114   CSingleLock lock(m_critSection);
115   if (rBuf.getBuffer() == NULL)
116     rBuf.Create(size);
117
118   bool bOk = size <= rBuf.getMaxWriteSize() && size <= getMaxReadSize();
119   if (bOk)
120   {
121     unsigned int chunksize = std::min(size, m_size - m_readPtr);
122     bOk = rBuf.WriteData(&getBuffer()[m_readPtr], chunksize);
123     if (bOk && chunksize < size)
124       bOk = rBuf.WriteData(&getBuffer()[0], size - chunksize);
125     if (bOk)
126       SkipBytes(size);
127   }
128
129   return bOk;
130 }
131
132 /* Write data to ring buffer from buffer specified in 'buf'. Amount read in is
133  * specified by 'size'.
134  */
135 bool CRingBuffer::WriteData(const char *buf, unsigned int size)
136 {
137   CSingleLock lock(m_critSection);
138   if (size > m_size - m_fillCount)
139   {
140     return false;
141   }
142   if (size + m_writePtr > m_size)
143   {
144     unsigned int chunk = m_size - m_writePtr;
145     memcpy(m_buffer + m_writePtr, buf, chunk);
146     memcpy(m_buffer, buf + chunk, size - chunk);
147     m_writePtr = size - chunk;
148   }
149   else
150   {
151     memcpy(m_buffer + m_writePtr, buf, size);
152     m_writePtr += size;
153   }
154   if (m_writePtr == m_size)
155     m_writePtr = 0;
156   m_fillCount += size;
157   return true;
158 }
159
160 /* Write data to ring buffer from another ring buffer object specified by
161  * 'rBuf'.
162  */
163 bool CRingBuffer::WriteData(CRingBuffer &rBuf, unsigned int size)
164 {
165   CSingleLock lock(m_critSection);
166   if (m_buffer == NULL)
167     Create(size);
168
169   bool bOk = size <= rBuf.getMaxReadSize() && size <= getMaxWriteSize();
170   if (bOk)
171   {
172     unsigned int readpos = rBuf.getReadPtr();
173     unsigned int chunksize = std::min(size, rBuf.getSize() - readpos);
174     bOk = WriteData(&rBuf.getBuffer()[readpos], chunksize);
175     if (bOk && chunksize < size)
176       bOk = WriteData(&rBuf.getBuffer()[0], size - chunksize);
177   }
178
179   return bOk;
180 }
181
182 /* Skip bytes in buffer to be read */
183 bool CRingBuffer::SkipBytes(int skipSize)
184 {
185   CSingleLock lock(m_critSection);
186   if (skipSize < 0)
187   {
188     return false; // skipping backwards is not supported
189   }
190
191   unsigned int size = skipSize;
192   if (size > m_fillCount)
193   {
194     return false;
195   }
196   if (size + m_readPtr > m_size)
197   {
198     unsigned int chunk = m_size - m_readPtr;
199     m_readPtr = size - chunk;
200   }
201   else
202   {
203     m_readPtr += size;
204   }
205   if (m_readPtr == m_size)
206     m_readPtr = 0;
207   m_fillCount -= size;
208   return true;
209 }
210
211 /* Append all content from ring buffer 'rBuf' to this ring buffer */
212 bool CRingBuffer::Append(CRingBuffer &rBuf)
213 {
214   return WriteData(rBuf, rBuf.getMaxReadSize());
215 }
216
217 /* Copy all content from ring buffer 'rBuf' to this ring buffer overwriting any existing data */
218 bool CRingBuffer::Copy(CRingBuffer &rBuf)
219 {
220   Clear();
221   return Append(rBuf);
222 }
223
224 /* Our various 'get' methods */
225 char *CRingBuffer::getBuffer()
226 {
227   return m_buffer;
228 }
229
230 unsigned int CRingBuffer::getSize()
231 {
232   CSingleLock lock(m_critSection);
233   return m_size;
234 }
235
236 unsigned int CRingBuffer::getReadPtr()
237 {
238   return m_readPtr;
239 }
240
241 unsigned int CRingBuffer::getWritePtr()
242 {
243   CSingleLock lock(m_critSection);
244   return m_writePtr;
245 }
246
247 unsigned int CRingBuffer::getMaxReadSize()
248 {
249   CSingleLock lock(m_critSection);
250   return m_fillCount;
251 }
252
253 unsigned int CRingBuffer::getMaxWriteSize()
254 {
255   CSingleLock lock(m_critSection);
256   return m_size - m_fillCount;
257 }