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
MemoryInputStream(const void * sourceData,size_t sourceDataSize,bool keepCopy)26 MemoryInputStream::MemoryInputStream (const void* sourceData, size_t sourceDataSize, bool keepCopy)
27 : data (sourceData),
28 dataSize (sourceDataSize)
29 {
30 if (keepCopy)
31 {
32 internalCopy = MemoryBlock (sourceData, sourceDataSize);
33 data = internalCopy.getData();
34 }
35 }
36
MemoryInputStream(const MemoryBlock & sourceData,bool keepCopy)37 MemoryInputStream::MemoryInputStream (const MemoryBlock& sourceData, bool keepCopy)
38 : data (sourceData.getData()),
39 dataSize (sourceData.getSize())
40 {
41 if (keepCopy)
42 {
43 internalCopy = sourceData;
44 data = internalCopy.getData();
45 }
46 }
47
MemoryInputStream(MemoryBlock && source)48 MemoryInputStream::MemoryInputStream (MemoryBlock&& source)
49 : internalCopy (std::move (source))
50 {
51 data = internalCopy.getData();
52 }
53
~MemoryInputStream()54 MemoryInputStream::~MemoryInputStream()
55 {
56 }
57
getTotalLength()58 int64 MemoryInputStream::getTotalLength()
59 {
60 return (int64) dataSize;
61 }
62
read(void * buffer,int howMany)63 int MemoryInputStream::read (void* buffer, int howMany)
64 {
65 jassert (buffer != nullptr && howMany >= 0);
66
67 if (howMany <= 0 || position >= dataSize)
68 return 0;
69
70 auto num = jmin ((size_t) howMany, dataSize - position);
71
72 if (num > 0)
73 {
74 memcpy (buffer, addBytesToPointer (data, position), num);
75 position += num;
76 }
77
78 return (int) num;
79 }
80
isExhausted()81 bool MemoryInputStream::isExhausted()
82 {
83 return position >= dataSize;
84 }
85
setPosition(const int64 pos)86 bool MemoryInputStream::setPosition (const int64 pos)
87 {
88 position = (size_t) jlimit ((int64) 0, (int64) dataSize, pos);
89 return true;
90 }
91
getPosition()92 int64 MemoryInputStream::getPosition()
93 {
94 return (int64) position;
95 }
96
skipNextBytes(int64 numBytesToSkip)97 void MemoryInputStream::skipNextBytes (int64 numBytesToSkip)
98 {
99 if (numBytesToSkip > 0)
100 setPosition (getPosition() + numBytesToSkip);
101 }
102
103
104 //==============================================================================
105 //==============================================================================
106 #if JUCE_UNIT_TESTS
107
108 class MemoryStreamTests : public UnitTest
109 {
110 public:
MemoryStreamTests()111 MemoryStreamTests()
112 : UnitTest ("MemoryInputStream & MemoryOutputStream", UnitTestCategories::streams)
113 {}
114
runTest()115 void runTest() override
116 {
117 beginTest ("Basics");
118 Random r = getRandom();
119
120 int randomInt = r.nextInt();
121 int64 randomInt64 = r.nextInt64();
122 double randomDouble = r.nextDouble();
123 String randomString (createRandomWideCharString (r));
124
125 MemoryOutputStream mo;
126 mo.writeInt (randomInt);
127 mo.writeIntBigEndian (randomInt);
128 mo.writeCompressedInt (randomInt);
129 mo.writeString (randomString);
130 mo.writeInt64 (randomInt64);
131 mo.writeInt64BigEndian (randomInt64);
132 mo.writeDouble (randomDouble);
133 mo.writeDoubleBigEndian (randomDouble);
134
135 MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
136 expect (mi.readInt() == randomInt);
137 expect (mi.readIntBigEndian() == randomInt);
138 expect (mi.readCompressedInt() == randomInt);
139 expectEquals (mi.readString(), randomString);
140 expect (mi.readInt64() == randomInt64);
141 expect (mi.readInt64BigEndian() == randomInt64);
142 expect (mi.readDouble() == randomDouble);
143 expect (mi.readDoubleBigEndian() == randomDouble);
144
145 const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
146 MemoryInputStream stream (data, true);
147
148 beginTest ("Read");
149
150 expectEquals (stream.getPosition(), (int64) 0);
151 expectEquals (stream.getTotalLength(), (int64) data.getSize());
152 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
153 expect (! stream.isExhausted());
154
155 size_t numBytesRead = 0;
156 MemoryBlock readBuffer (data.getSize());
157
158 while (numBytesRead < data.getSize())
159 {
160 numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
161
162 expectEquals (stream.getPosition(), (int64) numBytesRead);
163 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
164 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
165 }
166
167 expectEquals (stream.getPosition(), (int64) data.getSize());
168 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
169 expect (stream.isExhausted());
170
171 expect (readBuffer == data);
172
173 beginTest ("Skip");
174
175 stream.setPosition (0);
176 expectEquals (stream.getPosition(), (int64) 0);
177 expectEquals (stream.getTotalLength(), (int64) data.getSize());
178 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
179 expect (! stream.isExhausted());
180
181 numBytesRead = 0;
182 const int numBytesToSkip = 5;
183
184 while (numBytesRead < data.getSize())
185 {
186 stream.skipNextBytes (numBytesToSkip);
187 numBytesRead += numBytesToSkip;
188 numBytesRead = std::min (numBytesRead, data.getSize());
189
190 expectEquals (stream.getPosition(), (int64) numBytesRead);
191 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
192 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
193 }
194
195 expectEquals (stream.getPosition(), (int64) data.getSize());
196 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
197 expect (stream.isExhausted());
198 }
199
createRandomWideCharString(Random & r)200 static String createRandomWideCharString (Random& r)
201 {
202 juce_wchar buffer [50] = { 0 };
203
204 for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
205 {
206 if (r.nextBool())
207 {
208 do
209 {
210 buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
211 }
212 while (! CharPointer_UTF16::canRepresent (buffer[i]));
213 }
214 else
215 buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
216 }
217
218 return CharPointer_UTF32 (buffer);
219 }
220 };
221
222 static MemoryStreamTests memoryInputStreamUnitTests;
223
224 #endif
225
226 } // namespace juce
227