OpenShot Audio Library | OpenShotAudio  0.3.2
juce_BufferedInputStream.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 static inline int calcBufferStreamBufferSize (int requestedSize, InputStream* source) noexcept
27 {
28  // You need to supply a real stream when creating a BufferedInputStream
29  jassert (source != nullptr);
30 
31  requestedSize = jmax (256, requestedSize);
32  auto sourceSize = source->getTotalLength();
33 
34  if (sourceSize >= 0 && sourceSize < requestedSize)
35  return jmax (32, (int) sourceSize);
36 
37  return requestedSize;
38 }
39 
40 //==============================================================================
41 BufferedInputStream::BufferedInputStream (InputStream* sourceStream, int size, bool takeOwnership)
42  : source (sourceStream, takeOwnership),
43  bufferSize (calcBufferStreamBufferSize (size, sourceStream)),
44  position (sourceStream->getPosition()),
45  bufferStart (position)
46 {
47  buffer.malloc (bufferSize);
48 }
49 
51  : BufferedInputStream (&sourceStream, size, false)
52 {
53 }
54 
56 {
57 }
58 
59 //==============================================================================
61 {
62  if (! ensureBuffered())
63  return 0;
64 
65  return position < lastReadPos ? buffer[(int) (position - bufferStart)] : 0;
66 }
67 
69 {
70  return source->getTotalLength();
71 }
72 
74 {
75  return position;
76 }
77 
78 bool BufferedInputStream::setPosition (int64 newPosition)
79 {
80  position = jmax ((int64) 0, newPosition);
81  return true;
82 }
83 
85 {
86  return position >= lastReadPos && source->isExhausted();
87 }
88 
89 bool BufferedInputStream::ensureBuffered()
90 {
91  auto bufferEndOverlap = lastReadPos - bufferOverlap;
92 
93  if (position < bufferStart || position >= bufferEndOverlap)
94  {
95  int bytesRead;
96 
97  if (position < lastReadPos
98  && position >= bufferEndOverlap
99  && position >= bufferStart)
100  {
101  auto bytesToKeep = (int) (lastReadPos - position);
102  memmove (buffer, buffer + (int) (position - bufferStart), (size_t) bytesToKeep);
103 
104  bufferStart = position;
105  bytesRead = source->read (buffer + bytesToKeep,
106  (int) (bufferSize - bytesToKeep));
107 
108  if (bytesRead < 0)
109  return false;
110 
111  lastReadPos += bytesRead;
112  bytesRead += bytesToKeep;
113  }
114  else
115  {
116  bufferStart = position;
117 
118  if (! source->setPosition (bufferStart))
119  return false;
120 
121  bytesRead = source->read (buffer, bufferSize);
122 
123  if (bytesRead < 0)
124  return false;
125 
126  lastReadPos = bufferStart + bytesRead;
127  }
128 
129  while (bytesRead < bufferSize)
130  buffer[bytesRead++] = 0;
131  }
132 
133  return true;
134 }
135 
136 int BufferedInputStream::read (void* destBuffer, int maxBytesToRead)
137 {
138  jassert (destBuffer != nullptr && maxBytesToRead >= 0);
139 
140  if (position >= bufferStart
141  && position + maxBytesToRead <= lastReadPos)
142  {
143  memcpy (destBuffer, buffer + (int) (position - bufferStart), (size_t) maxBytesToRead);
144  position += maxBytesToRead;
145  return maxBytesToRead;
146  }
147 
148  if (position < bufferStart || position >= lastReadPos)
149  if (! ensureBuffered())
150  return 0;
151 
152  int bytesRead = 0;
153 
154  while (maxBytesToRead > 0)
155  {
156  auto numToRead = jmin (maxBytesToRead, (int) (lastReadPos - position));
157 
158  if (numToRead > 0)
159  {
160  memcpy (destBuffer, buffer + (int) (position - bufferStart), (size_t) numToRead);
161  maxBytesToRead -= numToRead;
162  bytesRead += numToRead;
163  position += numToRead;
164  destBuffer = static_cast<char*> (destBuffer) + numToRead;
165  }
166 
167  auto oldLastReadPos = lastReadPos;
168 
169  if (! ensureBuffered()
170  || oldLastReadPos == lastReadPos
171  || isExhausted())
172  break;
173  }
174 
175  return bytesRead;
176 }
177 
179 {
180  if (position >= bufferStart
181  && position < lastReadPos)
182  {
183  auto maxChars = (int) (lastReadPos - position);
184  auto* src = buffer + (int) (position - bufferStart);
185 
186  for (int i = 0; i < maxChars; ++i)
187  {
188  if (src[i] == 0)
189  {
190  position += i + 1;
191  return String::fromUTF8 (src, i);
192  }
193  }
194  }
195 
196  return InputStream::readString();
197 }
198 
199 
200 //==============================================================================
201 //==============================================================================
202 #if JUCE_UNIT_TESTS
203 
204 struct BufferedInputStreamTests : public UnitTest
205 {
206  BufferedInputStreamTests()
207  : UnitTest ("BufferedInputStream", UnitTestCategories::streams)
208  {}
209 
210  void runTest() override
211  {
212  const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
213  MemoryInputStream mi (data, true);
214 
215  BufferedInputStream stream (mi, (int) data.getSize());
216 
217  beginTest ("Read");
218 
219  expectEquals (stream.getPosition(), (int64) 0);
220  expectEquals (stream.getTotalLength(), (int64) data.getSize());
221  expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
222  expect (! stream.isExhausted());
223 
224  size_t numBytesRead = 0;
225  MemoryBlock readBuffer (data.getSize());
226 
227  while (numBytesRead < data.getSize())
228  {
229  expectEquals (stream.peekByte(), *(char*) (data.begin() + numBytesRead));
230 
231  numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
232 
233  expectEquals (stream.getPosition(), (int64) numBytesRead);
234  expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
235  expect (stream.isExhausted() == (numBytesRead == data.getSize()));
236  }
237 
238  expectEquals (stream.getPosition(), (int64) data.getSize());
239  expectEquals (stream.getNumBytesRemaining(), (int64) 0);
240  expect (stream.isExhausted());
241 
242  expect (readBuffer == data);
243 
244  beginTest ("Skip");
245 
246  stream.setPosition (0);
247  expectEquals (stream.getPosition(), (int64) 0);
248  expectEquals (stream.getTotalLength(), (int64) data.getSize());
249  expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
250  expect (! stream.isExhausted());
251 
252  numBytesRead = 0;
253  const int numBytesToSkip = 5;
254 
255  while (numBytesRead < data.getSize())
256  {
257  expectEquals (stream.peekByte(), *(char*) (data.begin() + numBytesRead));
258 
259  stream.skipNextBytes (numBytesToSkip);
260  numBytesRead += numBytesToSkip;
261  numBytesRead = std::min (numBytesRead, data.getSize());
262 
263  expectEquals (stream.getPosition(), (int64) numBytesRead);
264  expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
265  expect (stream.isExhausted() == (numBytesRead == data.getSize()));
266  }
267 
268  expectEquals (stream.getPosition(), (int64) data.getSize());
269  expectEquals (stream.getNumBytesRemaining(), (int64) 0);
270  expect (stream.isExhausted());
271  }
272 };
273 
274 static BufferedInputStreamTests bufferedInputStreamTests;
275 
276 #endif
277 
278 } // namespace juce
BufferedInputStream(InputStream *sourceStream, int bufferSize, bool deleteSourceWhenDestroyed)
int read(void *destBuffer, int maxBytesToRead) override
bool setPosition(int64 newPosition) override
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
virtual String readString()
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)