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 
26 int64 juce_fileSetPosition (void* handle, int64 pos);
27 
28 
29 //==============================================================================
FileInputStream(const File & f)30 FileInputStream::FileInputStream (const File& f)  : file (f)
31 {
32     openHandle();
33 }
34 
getTotalLength()35 int64 FileInputStream::getTotalLength()
36 {
37     // You should always check that a stream opened successfully before using it!
38     jassert (openedOk());
39 
40     return file.getSize();
41 }
42 
read(void * buffer,int bytesToRead)43 int FileInputStream::read (void* buffer, int bytesToRead)
44 {
45     // You should always check that a stream opened successfully before using it!
46     jassert (openedOk());
47 
48     // The buffer should never be null, and a negative size is probably a
49     // sign that something is broken!
50     jassert (buffer != nullptr && bytesToRead >= 0);
51 
52     auto num = readInternal (buffer, (size_t) bytesToRead);
53     currentPosition += (int64) num;
54 
55     return (int) num;
56 }
57 
isExhausted()58 bool FileInputStream::isExhausted()
59 {
60     return currentPosition >= getTotalLength();
61 }
62 
getPosition()63 int64 FileInputStream::getPosition()
64 {
65     return currentPosition;
66 }
67 
setPosition(int64 pos)68 bool FileInputStream::setPosition (int64 pos)
69 {
70     // You should always check that a stream opened successfully before using it!
71     jassert (openedOk());
72 
73     if (pos != currentPosition)
74         currentPosition = juce_fileSetPosition (fileHandle, pos);
75 
76     return currentPosition == pos;
77 }
78 
79 
80 //==============================================================================
81 //==============================================================================
82 #if JUCE_UNIT_TESTS
83 
84 struct FileInputStreamTests   : public UnitTest
85 {
FileInputStreamTestsjuce::FileInputStreamTests86     FileInputStreamTests()
87         : UnitTest ("FileInputStream", UnitTestCategories::streams)
88     {}
89 
runTestjuce::FileInputStreamTests90     void runTest() override
91     {
92         beginTest ("Open stream non-existent file");
93         {
94             auto tempFile = File::createTempFile (".txt");
95             expect (! tempFile.exists());
96 
97             FileInputStream stream (tempFile);
98             expect (stream.failedToOpen());
99         }
100 
101         beginTest ("Open stream existing file");
102         {
103             auto tempFile = File::createTempFile (".txt");
104             tempFile.create();
105             expect (tempFile.exists());
106 
107             FileInputStream stream (tempFile);
108             expect (stream.openedOk());
109         }
110 
111         const MemoryBlock data ("abcdefghijklmnopqrstuvwxyz", 26);
112         File f (File::createTempFile (".txt"));
113         f.appendData (data.getData(), data.getSize());
114         FileInputStream stream (f);
115 
116         beginTest ("Read");
117         {
118             expectEquals (stream.getPosition(), (int64) 0);
119             expectEquals (stream.getTotalLength(), (int64) data.getSize());
120             expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
121             expect (! stream.isExhausted());
122 
123             size_t numBytesRead = 0;
124             MemoryBlock readBuffer (data.getSize());
125 
126             while (numBytesRead < data.getSize())
127             {
128                 numBytesRead += (size_t) stream.read (&readBuffer[numBytesRead], 3);
129 
130                 expectEquals (stream.getPosition(), (int64) numBytesRead);
131                 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
132                 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
133             }
134 
135             expectEquals (stream.getPosition(), (int64) data.getSize());
136             expectEquals (stream.getNumBytesRemaining(), (int64) 0);
137             expect (stream.isExhausted());
138 
139             expect (readBuffer == data);
140         }
141 
142         beginTest ("Skip");
143         {
144             stream.setPosition (0);
145             expectEquals (stream.getPosition(), (int64) 0);
146             expectEquals (stream.getTotalLength(), (int64) data.getSize());
147             expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
148             expect (! stream.isExhausted());
149 
150             size_t numBytesRead = 0;
151             const int numBytesToSkip = 5;
152 
153             while (numBytesRead < data.getSize())
154             {
155                 stream.skipNextBytes (numBytesToSkip);
156                 numBytesRead += numBytesToSkip;
157                 numBytesRead = std::min (numBytesRead, data.getSize());
158 
159                 expectEquals (stream.getPosition(), (int64) numBytesRead);
160                 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
161                 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
162             }
163 
164             expectEquals (stream.getPosition(), (int64) data.getSize());
165             expectEquals (stream.getNumBytesRemaining(), (int64) 0);
166             expect (stream.isExhausted());
167 
168             f.deleteFile();
169         }
170     }
171 };
172 
173 static FileInputStreamTests fileInputStreamTests;
174 
175 #endif
176 
177 } // namespace juce
178