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