JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_ZipFile.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - 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
23namespace juce
24{
25
26inline uint16 readUnalignedLittleEndianShort (const void* buffer)
27{
28 auto data = readUnaligned<uint16> (buffer);
29 return ByteOrder::littleEndianShort (&data);
30}
31
32inline uint32 readUnalignedLittleEndianInt (const void* buffer)
33{
34 auto data = readUnaligned<uint32> (buffer);
35 return ByteOrder::littleEndianInt (&data);
36}
37
39{
40 ZipEntryHolder (const char* buffer, int fileNameLen)
41 {
42 isCompressed = readUnalignedLittleEndianShort (buffer + 10) != 0;
43 entry.fileTime = parseFileTime (readUnalignedLittleEndianShort (buffer + 12),
44 readUnalignedLittleEndianShort (buffer + 14));
45 compressedSize = (int64) readUnalignedLittleEndianInt (buffer + 20);
46 entry.uncompressedSize = (int64) readUnalignedLittleEndianInt (buffer + 24);
47 streamOffset = (int64) readUnalignedLittleEndianInt (buffer + 42);
48
49 entry.externalFileAttributes = readUnalignedLittleEndianInt (buffer + 38);
50 auto fileType = (entry.externalFileAttributes >> 28) & 0xf;
51 entry.isSymbolicLink = (fileType == 0xA);
52
53 entry.filename = String::fromUTF8 (buffer + 46, fileNameLen);
54 }
55
56 static Time parseFileTime (uint32 time, uint32 date) noexcept
57 {
58 auto year = (int) (1980 + (date >> 9));
59 auto month = (int) (((date >> 5) & 15) - 1);
60 auto day = (int) (date & 31);
61 auto hours = (int) time >> 11;
62 auto minutes = (int) ((time >> 5) & 63);
63 auto seconds = (int) ((time & 31) << 1);
64
65 return { year, month, day, hours, minutes, seconds };
66 }
67
68 ZipEntry entry;
69 int64 streamOffset, compressedSize;
70 bool isCompressed;
71};
72
73//==============================================================================
74static int64 findCentralDirectoryFileHeader (InputStream& input, int& numEntries)
75{
76 BufferedInputStream in (input, 8192);
77
78 in.setPosition (in.getTotalLength());
79 auto pos = in.getPosition();
80 auto lowestPos = jmax ((int64) 0, pos - 1048576);
81 char buffer[32] = {};
82
83 while (pos > lowestPos)
84 {
85 in.setPosition (pos - 22);
86 pos = in.getPosition();
87 memcpy (buffer + 22, buffer, 4);
88
89 if (in.read (buffer, 22) != 22)
90 return 0;
91
92 for (int i = 0; i < 22; ++i)
93 {
94 if (readUnalignedLittleEndianInt (buffer + i) == 0x06054b50)
95 {
96 in.setPosition (pos + i);
97 in.read (buffer, 22);
98 numEntries = readUnalignedLittleEndianShort (buffer + 10);
99 auto offset = (int64) readUnalignedLittleEndianInt (buffer + 16);
100
101 if (offset >= 4)
102 {
103 in.setPosition (offset);
104
105 // This is a workaround for some zip files which seem to contain the
106 // wrong offset for the central directory - instead of including the
107 // header, they point to the byte immediately after it.
108 if (in.readInt() != 0x02014b50)
109 {
110 in.setPosition (offset - 4);
111
112 if (in.readInt() == 0x02014b50)
113 offset -= 4;
114 }
115 }
116
117 return offset;
118 }
119 }
120 }
121
122 return 0;
123}
124
125static bool hasSymbolicPart (const File& root, const File& f)
126{
127 jassert (root == f || f.isAChildOf (root));
128
129 for (auto p = f; p != root; p = p.getParentDirectory())
130 {
131 if (p.isSymbolicLink())
132 return true;
133 }
134
135 return false;
136}
137
138//==============================================================================
140{
142 : file (zf),
143 zipEntryHolder (zei),
144 inputStream (zf.inputStream)
145 {
146 if (zf.inputSource != nullptr)
147 {
148 streamToDelete.reset (file.inputSource->createInputStream());
149 inputStream = streamToDelete.get();
150 }
151 else
152 {
153 #if JUCE_DEBUG
154 zf.streamCounter.numOpenStreams++;
155 #endif
156 }
157
158 char buffer[30];
159
160 if (inputStream != nullptr
161 && inputStream->setPosition (zei.streamOffset)
162 && inputStream->read (buffer, 30) == 30
163 && ByteOrder::littleEndianInt (buffer) == 0x04034b50)
164 {
165 headerSize = 30 + ByteOrder::littleEndianShort (buffer + 26)
166 + ByteOrder::littleEndianShort (buffer + 28);
167 }
168 }
169
170 ~ZipInputStream() override
171 {
172 #if JUCE_DEBUG
173 if (inputStream != nullptr && inputStream == file.inputStream)
174 file.streamCounter.numOpenStreams--;
175 #endif
176 }
177
179 {
180 return zipEntryHolder.compressedSize;
181 }
182
183 int read (void* buffer, int howMany) override
184 {
185 if (headerSize <= 0)
186 return 0;
187
188 howMany = (int) jmin ((int64) howMany, zipEntryHolder.compressedSize - pos);
189
190 if (inputStream == nullptr)
191 return 0;
192
193 int num;
194
195 if (inputStream == file.inputStream)
196 {
197 const ScopedLock sl (file.lock);
198 inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize);
199 num = inputStream->read (buffer, howMany);
200 }
201 else
202 {
203 inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize);
204 num = inputStream->read (buffer, howMany);
205 }
206
207 pos += num;
208 return num;
209 }
210
211 bool isExhausted() override
212 {
213 return headerSize <= 0 || pos >= zipEntryHolder.compressedSize;
214 }
215
217 {
218 return pos;
219 }
220
221 bool setPosition (int64 newPos) override
222 {
223 pos = jlimit ((int64) 0, zipEntryHolder.compressedSize, newPos);
224 return true;
225 }
226
227private:
228 ZipFile& file;
229 ZipEntryHolder zipEntryHolder;
230 int64 pos = 0;
231 int headerSize = 0;
232 InputStream* inputStream;
233 std::unique_ptr<InputStream> streamToDelete;
234
236};
237
238
239//==============================================================================
241 : inputStream (stream)
242{
244 streamToDelete.reset (inputStream);
245
246 init();
247}
248
249ZipFile::ZipFile (InputStream& stream) : inputStream (&stream)
250{
251 init();
252}
253
254ZipFile::ZipFile (const File& file) : inputSource (new FileInputSource (file))
255{
256 init();
257}
258
259ZipFile::ZipFile (InputSource* source) : inputSource (source)
260{
261 init();
262}
263
265{
266 entries.clear();
267}
268
269#if JUCE_DEBUG
270ZipFile::OpenStreamCounter::~OpenStreamCounter()
271{
272 /* If you hit this assertion, it means you've created a stream to read one of the items in the
273 zipfile, but you've forgotten to delete that stream object before deleting the file..
274 Streams can't be kept open after the file is deleted because they need to share the input
275 stream that is managed by the ZipFile object.
276 */
277 jassert (numOpenStreams == 0);
278}
279#endif
280
281//==============================================================================
283{
284 return entries.size();
285}
286
287const ZipFile::ZipEntry* ZipFile::getEntry (const int index) const noexcept
288{
289 if (auto* zei = entries[index])
290 return &(zei->entry);
291
292 return nullptr;
293}
294
295int ZipFile::getIndexOfFileName (const String& fileName, bool ignoreCase) const noexcept
296{
297 for (int i = 0; i < entries.size(); ++i)
298 {
299 auto& entryFilename = entries.getUnchecked (i)->entry.filename;
300
301 if (ignoreCase ? entryFilename.equalsIgnoreCase (fileName)
303 return i;
304 }
305
306 return -1;
307}
308
309const ZipFile::ZipEntry* ZipFile::getEntry (const String& fileName, bool ignoreCase) const noexcept
310{
311 return getEntry (getIndexOfFileName (fileName, ignoreCase));
312}
313
315{
316 InputStream* stream = nullptr;
317
318 if (auto* zei = entries[index])
319 {
320 stream = new ZipInputStream (*this, *zei);
321
322 if (zei->isCompressed)
323 {
324 stream = new GZIPDecompressorInputStream (stream, true,
325 GZIPDecompressorInputStream::deflateFormat,
326 zei->entry.uncompressedSize);
327
328 // (much faster to unzip in big blocks using a buffer..)
329 stream = new BufferedInputStream (stream, 32768, true);
330 }
331 }
332
333 return stream;
334}
335
337{
338 for (int i = 0; i < entries.size(); ++i)
339 if (&entries.getUnchecked (i)->entry == &entry)
340 return createStreamForEntry (i);
341
342 return nullptr;
343}
344
346{
347 std::sort (entries.begin(), entries.end(),
348 [] (const ZipEntryHolder* e1, const ZipEntryHolder* e2) { return e1->entry.filename < e2->entry.filename; });
349}
350
351//==============================================================================
352void ZipFile::init()
353{
355 InputStream* in = inputStream;
356
357 if (inputSource != nullptr)
358 {
359 in = inputSource->createInputStream();
360 toDelete.reset (in);
361 }
362
363 if (in != nullptr)
364 {
365 int numEntries = 0;
366 auto centralDirectoryPos = findCentralDirectoryFileHeader (*in, numEntries);
367
368 if (centralDirectoryPos >= 0 && centralDirectoryPos < in->getTotalLength())
369 {
370 auto size = (size_t) (in->getTotalLength() - centralDirectoryPos);
371
373 MemoryBlock headerData;
374
375 if (in->readIntoMemoryBlock (headerData, (ssize_t) size) == size)
376 {
377 size_t pos = 0;
378
379 for (int i = 0; i < numEntries; ++i)
380 {
381 if (pos + 46 > size)
382 break;
383
384 auto* buffer = static_cast<const char*> (headerData.getData()) + pos;
385 auto fileNameLen = readUnalignedLittleEndianShort (buffer + 28u);
386
387 if (pos + 46 + fileNameLen > size)
388 break;
389
390 entries.add (new ZipEntryHolder (buffer, fileNameLen));
391
392 pos += 46u + fileNameLen
393 + readUnalignedLittleEndianShort (buffer + 30u)
394 + readUnalignedLittleEndianShort (buffer + 32u);
395 }
396 }
397 }
398 }
399}
400
402 const bool shouldOverwriteFiles)
403{
404 for (int i = 0; i < entries.size(); ++i)
405 {
407
408 if (result.failed())
409 return result;
410 }
411
412 return Result::ok();
413}
414
416{
417 return uncompressEntry (index,
419 shouldOverwriteFiles ? OverwriteFiles::yes : OverwriteFiles::no,
420 FollowSymlinks::no);
421}
422
423Result ZipFile::uncompressEntry (int index, const File& targetDirectory, OverwriteFiles overwriteFiles, FollowSymlinks followSymlinks)
424{
425 auto* zei = entries.getUnchecked (index);
426
427 #if JUCE_WINDOWS
428 auto entryPath = zei->entry.filename;
429 #else
430 auto entryPath = zei->entry.filename.replaceCharacter ('\\', '/');
431 #endif
432
433 if (entryPath.isEmpty())
434 return Result::ok();
435
436 auto targetFile = targetDirectory.getChildFile (entryPath);
437
438 if (! targetFile.isAChildOf (targetDirectory))
439 return Result::fail ("Entry " + entryPath + " is outside the target directory");
440
441 if (entryPath.endsWithChar ('/') || entryPath.endsWithChar ('\\'))
442 return targetFile.createDirectory(); // (entry is a directory, not a file)
443
445
446 if (in == nullptr)
447 return Result::fail ("Failed to open the zip file for reading");
448
449 if (targetFile.exists())
450 {
451 if (overwriteFiles == OverwriteFiles::no)
452 return Result::ok();
453
454 if (! targetFile.deleteFile())
455 return Result::fail ("Failed to write to target file: " + targetFile.getFullPathName());
456 }
457
458 if (followSymlinks == FollowSymlinks::no && hasSymbolicPart (targetDirectory, targetFile.getParentDirectory()))
459 return Result::fail ("Parent directory leads through symlink for target file: " + targetFile.getFullPathName());
460
461 if (! targetFile.getParentDirectory().createDirectory())
462 return Result::fail ("Failed to create target folder: " + targetFile.getParentDirectory().getFullPathName());
463
464 if (zei->entry.isSymbolicLink)
465 {
466 String originalFilePath (in->readEntireStreamAsString()
467 .replaceCharacter (L'/', File::getSeparatorChar()));
468
469 if (! File::createSymbolicLink (targetFile, originalFilePath, true))
470 return Result::fail ("Failed to create symbolic link: " + originalFilePath);
471 }
472 else
473 {
474 FileOutputStream out (targetFile);
475
476 if (out.failedToOpen())
477 return Result::fail ("Failed to write to target file: " + targetFile.getFullPathName());
478
479 out << *in;
480 }
481
482 targetFile.setCreationTime (zei->entry.fileTime);
483 targetFile.setLastModificationTime (zei->entry.fileTime);
484 targetFile.setLastAccessTime (zei->entry.fileTime);
485
486 return Result::ok();
487}
488
489
490//==============================================================================
492{
493 Item (const File& f, InputStream* s, int compression, const String& storedPath, Time time)
494 : file (f), stream (s), storedPathname (storedPath), fileTime (time), compressionLevel (compression)
495 {
496 symbolicLink = (file.exists() && file.isSymbolicLink());
497 }
498
499 bool writeData (OutputStream& target, const int64 overallStartPosition)
500 {
501 MemoryOutputStream compressedData ((size_t) file.getSize());
502
503 if (symbolicLink)
504 {
506
507 uncompressedSize = relativePath.length();
508
509 checksum = zlibNamespace::crc32 (0, (uint8_t*) relativePath.toRawUTF8(), (unsigned int) uncompressedSize);
511 }
512 else if (compressionLevel > 0)
513 {
515 GZIPCompressorOutputStream::windowBitsRaw);
516 if (! writeSource (compressor))
517 return false;
518 }
519 else
520 {
521 if (! writeSource (compressedData))
522 return false;
523 }
524
525 compressedSize = (int64) compressedData.getDataSize();
526 headerStart = target.getPosition() - overallStartPosition;
527
528 target.writeInt (0x04034b50);
529 writeFlagsAndSizes (target);
530 target << storedPathname
532
533 return true;
534 }
535
536 bool writeDirectoryEntry (OutputStream& target)
537 {
538 target.writeInt (0x02014b50);
539 target.writeShort (symbolicLink ? 0x0314 : 0x0014);
540 writeFlagsAndSizes (target);
541 target.writeShort (0); // comment length
542 target.writeShort (0); // start disk num
543 target.writeShort (0); // internal attributes
544 target.writeInt ((int) (symbolicLink ? 0xA1ED0000 : 0)); // external attributes
545 target.writeInt ((int) (uint32) headerStart);
546 target << storedPathname;
547
548 return true;
549 }
550
551private:
552 const File file;
554 String storedPathname;
555 Time fileTime;
556 int64 compressedSize = 0, uncompressedSize = 0, headerStart = 0;
557 int compressionLevel = 0;
558 unsigned long checksum = 0;
559 bool symbolicLink = false;
560
561 static void writeTimeAndDate (OutputStream& target, Time t)
562 {
563 target.writeShort ((short) (t.getSeconds() + (t.getMinutes() << 5) + (t.getHours() << 11)));
564 target.writeShort ((short) (t.getDayOfMonth() + ((t.getMonth() + 1) << 5) + ((t.getYear() - 1980) << 9)));
565 }
566
567 bool writeSource (OutputStream& target)
568 {
569 if (stream == nullptr)
570 {
571 stream = file.createInputStream();
572
573 if (stream == nullptr)
574 return false;
575 }
576
577 checksum = 0;
578 uncompressedSize = 0;
579 const int bufferSize = 4096;
580 HeapBlock<unsigned char> buffer (bufferSize);
581
582 while (! stream->isExhausted())
583 {
584 auto bytesRead = stream->read (buffer, bufferSize);
585
586 if (bytesRead < 0)
587 return false;
588
589 checksum = zlibNamespace::crc32 (checksum, buffer, (unsigned int) bytesRead);
590 target.write (buffer, (size_t) bytesRead);
591 uncompressedSize += bytesRead;
592 }
593
594 stream.reset();
595 return true;
596 }
597
598 void writeFlagsAndSizes (OutputStream& target) const
599 {
600 target.writeShort (10); // version needed
601 target.writeShort ((short) (1 << 11)); // this flag indicates UTF-8 filename encoding
602 target.writeShort ((! symbolicLink && compressionLevel > 0) ? (short) 8 : (short) 0); //symlink target path is not compressed
603 writeTimeAndDate (target, fileTime);
604 target.writeInt ((int) checksum);
605 target.writeInt ((int) (uint32) compressedSize);
606 target.writeInt ((int) (uint32) uncompressedSize);
607 target.writeShort (static_cast<short> (storedPathname.toUTF8().sizeInBytes() - 1));
608 target.writeShort (0); // extra field length
609 }
610
612};
613
614//==============================================================================
617
618void ZipFile::Builder::addFile (const File& file, int compression, const String& path)
619{
620 items.add (new Item (file, nullptr, compression,
621 path.isEmpty() ? file.getFileName() : path,
623}
624
625void ZipFile::Builder::addEntry (InputStream* stream, int compression, const String& path, Time time)
626{
627 jassert (stream != nullptr); // must not be null!
628 jassert (path.isNotEmpty());
629 items.add (new Item ({}, stream, compression, path, time));
630}
631
632bool ZipFile::Builder::writeToStream (OutputStream& target, double* const progress) const
633{
634 auto fileStart = target.getPosition();
635
636 for (int i = 0; i < items.size(); ++i)
637 {
638 if (progress != nullptr)
639 *progress = (i + 0.5) / items.size();
640
641 if (! items.getUnchecked (i)->writeData (target, fileStart))
642 return false;
643 }
644
645 auto directoryStart = target.getPosition();
646
647 for (auto* item : items)
648 if (! item->writeDirectoryEntry (target))
649 return false;
650
651 auto directoryEnd = target.getPosition();
652
653 target.writeInt (0x06054b50);
654 target.writeShort (0);
655 target.writeShort (0);
656 target.writeShort ((short) items.size());
657 target.writeShort ((short) items.size());
658 target.writeInt ((int) (directoryEnd - directoryStart));
659 target.writeInt ((int) (directoryStart - fileStart));
660 target.writeShort (0);
661
662 if (progress != nullptr)
663 *progress = 1.0;
664
665 return true;
666}
667
668
669//==============================================================================
670//==============================================================================
671#if JUCE_UNIT_TESTS
672
673struct ZIPTests final : public UnitTest
674{
675 ZIPTests()
676 : UnitTest ("ZIP", UnitTestCategories::compression)
677 {}
678
679 static MemoryBlock createZipMemoryBlock (const StringArray& entryNames)
680 {
681 ZipFile::Builder builder;
683
684 for (auto& entryName : entryNames)
685 {
686 auto& block = blocks.getReference (entryName);
687 MemoryOutputStream mo (block, false);
688 mo << entryName;
689 mo.flush();
690 builder.addEntry (new MemoryInputStream (block, false), 9, entryName, Time::getCurrentTime());
691 }
692
693 MemoryBlock data;
694 MemoryOutputStream mo (data, false);
695 builder.writeToStream (mo, nullptr);
696
697 return data;
698 }
699
700 void runZipSlipTest()
701 {
702 const std::map<String, bool> testCases = { { "a", true },
703#if JUCE_WINDOWS
704 { "C:/b", false },
705#else
706 { "/b", false },
707#endif
708 { "c/d", true },
709 { "../e/f", false },
710 { "../../g/h", false },
711 { "i/../j", true },
712 { "k/l/../", true },
713 { "m/n/../../", false },
714 { "o/p/../../../", false } };
715
716 StringArray entryNames;
717
718 for (const auto& testCase : testCases)
719 entryNames.add (testCase.first);
720
721 TemporaryFile tmpDir;
722 tmpDir.getFile().createDirectory();
723 auto data = createZipMemoryBlock (entryNames);
724 MemoryInputStream mi (data, false);
725 ZipFile zip (mi);
726
727 for (int i = 0; i < zip.getNumEntries(); ++i)
728 {
729 const auto result = zip.uncompressEntry (i, tmpDir.getFile());
730 const auto caseIt = testCases.find (zip.getEntry (i)->filename);
731
732 if (caseIt != testCases.end())
733 {
734 expect (result.wasOk() == caseIt->second,
735 zip.getEntry (i)->filename + " was unexpectedly " + (result.wasOk() ? "OK" : "not OK"));
736 }
737 else
738 {
739 expect (false);
740 }
741 }
742 }
743
744 void runTest() override
745 {
746 beginTest ("ZIP");
747
748 StringArray entryNames { "first", "second", "third" };
749 auto data = createZipMemoryBlock (entryNames);
750 MemoryInputStream mi (data, false);
751 ZipFile zip (mi);
752
753 expectEquals (zip.getNumEntries(), entryNames.size());
754
755 for (auto& entryName : entryNames)
756 {
757 auto* entry = zip.getEntry (entryName);
758 std::unique_ptr<InputStream> input (zip.createStreamForEntry (*entry));
759 expectEquals (input->readEntireStreamAsString(), entryName);
760 }
761
762 beginTest ("ZipSlip");
763 runZipSlipTest();
764 }
765};
766
767static ZIPTests zipTests;
768
769#endif
770
771} // namespace juce
Wraps another input stream, and reads from it using an intermediate buffer.
static constexpr uint32 littleEndianInt(const void *bytes) noexcept
Turns 4 bytes into a little-endian integer.
static constexpr uint16 littleEndianShort(const void *bytes) noexcept
Turns 2 bytes into a little-endian integer.
size_t sizeInBytes() const noexcept
Returns the number of bytes that are used to represent this string.
A type of InputSource that represents a normal file.
An output stream that writes into a local file.
bool failedToOpen() const noexcept
Returns true if the stream couldn't be opened for some reason.
Represents a local file or directory.
Definition juce_File.h:45
bool isSymbolicLink() const
Returns true if this file is a link or alias that can be followed using getLinkedTarget().
Time getLastModificationTime() const
Returns the last modification time of this file.
int64 getSize() const
Returns the size of the file in bytes.
String getFileName() const
Returns the last section of the pathname.
bool createSymbolicLink(const File &linkFileToCreate, bool overwriteExisting) const
Tries to create a symbolic link and returns a boolean to indicate success.
std::unique_ptr< FileInputStream > createInputStream() const
Creates a stream to read from this file.
static juce_wchar getSeparatorChar()
The system-specific file separator character.
String getNativeLinkedTarget() const
This returns the native path that the symbolic link points to.
bool exists() const
Checks whether the file actually exists.
A stream which uses zlib to compress the data written into it.
This stream will decompress a source-stream using zlib.
Automatically locks and unlocks a mutex object.
Holds a set of mappings between some key/value pairs.
ValueType & getReference(KeyTypeParameter keyToLookFor)
Returns a reference to the value corresponding to a given key.
Very simple container class to hold a pointer to some data on the heap.
A lightweight object that can create a stream to read some kind of resource.
The base class for streams that read data.
virtual bool setPosition(int64 newPosition)=0
Tries to move the current read position of the stream.
virtual int64 getTotalLength()=0
Returns the total number of bytes available for reading in this stream.
virtual size_t readIntoMemoryBlock(MemoryBlock &destBlock, ssize_t maxNumBytesToRead=-1)
Reads from the stream and appends the data to a MemoryBlock.
virtual int read(void *destBuffer, int maxBytesToRead)=0
Reads some data from the stream into a memory buffer.
virtual String readEntireStreamAsString()
Tries to read the whole stream and turn it into a string.
A class to hold a resizable block of raw data.
Allows a block of data to be accessed as a stream.
Writes data to an internal memory buffer, which grows as required.
The base class for streams that write data to some kind of destination.
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
virtual int64 getPosition()=0
Returns the stream's current position.
virtual bool writeShort(short value)
Writes a 16-bit integer to the stream in a little-endian byte order.
virtual bool writeInt(int value)
Writes a 32-bit integer to the stream in a little-endian byte order.
Represents the 'success' or 'failure' of an operation, and holds an associated error message to descr...
Definition juce_Result.h:57
static Result fail(const String &errorMessage) noexcept
Creates a 'failure' result.
static Result ok() noexcept
Creates and returns a 'successful' result.
Definition juce_Result.h:61
A special array for holding a list of strings.
The JUCE String class!
Definition juce_String.h:53
bool isEmpty() const noexcept
Returns true if the string contains no characters.
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Returns a string with all occurrences of a character replaced with a different one.
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
CharPointer_UTF8 toUTF8() const
Returns a pointer to a UTF-8 version of this string.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
Holds an absolute date and time.
Definition juce_Time.h:37
int getDayOfMonth() const noexcept
Returns the day of the month (in this machine's local timezone).
int getMonth() const noexcept
Returns the number of the month (in this machine's local timezone).
int getYear() const noexcept
Returns the year (in this machine's local timezone).
int getMinutes() const noexcept
Returns the number of minutes, 0 to 59 (in this machine's local timezone).
int getHours() const noexcept
Returns the number of hours since midnight (in this machine's local timezone).
int getSeconds() const noexcept
Returns the number of seconds, 0 to 59.
This is a base class for classes that perform a unit test.
Used to create a new zip file.
Builder()
Creates an empty builder object.
void addEntry(InputStream *streamToRead, int compressionLevel, const String &storedPathName, Time fileModificationTime)
Adds a stream to the list of items which will be added to the archive.
bool writeToStream(OutputStream &target, double *progress) const
Generates the zip file, writing it to the specified stream.
void addFile(const File &fileToAdd, int compressionLevel, const String &storedPathName=String())
Adds a file to the list of items which will be added to the archive.
Decodes a ZIP file from a stream.
Result uncompressTo(const File &targetDirectory, bool shouldOverwriteFiles=true)
Uncompresses all of the files in the zip file.
InputStream * createStreamForEntry(int index)
Creates a stream that can read from one of the zip file's entries.
const ZipEntry * getEntry(int index) const noexcept
Returns a structure that describes one of the entries in the zip file.
~ZipFile()
Destructor.
int getNumEntries() const noexcept
Returns the number of items in the zip file.
String filename
The name of the file, which may also include a partial pathname.
int64 uncompressedSize
The file's original size.
ZipFile(const File &file)
Creates a ZipFile to read a specific file.
uint32 externalFileAttributes
Platform specific data.
bool isSymbolicLink
True if the zip entry is a symbolic link.
Result uncompressEntry(int index, const File &targetDirectory, bool shouldOverwriteFiles=true)
Uncompresses one of the entries from the zip file.
int getIndexOfFileName(const String &fileName, bool ignoreCase=false) const noexcept
Returns the index of the first entry with a given filename.
void sortEntriesByFilename()
Sorts the list of entries, based on the filename.
Time fileTime
The last time the file was modified.
Contains information about one of the entries in a ZipFile.
T data(T... args)
T end(T... args)
T find(T... args)
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
typedef int
memcpy
JUCE Namespace.
unsigned short uint16
A platform-independent 16-bit unsigned integer type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
Constrains a value to keep it within a given range.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
T reset(T... args)
T sort(T... args)
typedef uint8_t
int read(void *buffer, int howMany) override
Reads some data from the stream into a memory buffer.
bool isExhausted() override
Returns true if the stream has no more data to read.
bool setPosition(int64 newPos) override
Tries to move the current read position of the stream.
int64 getTotalLength() override
Returns the total number of bytes available for reading in this stream.
int64 getPosition() override
Returns the offset of the next byte that will be read from the stream.
typedef size_t
time