OpenShot Audio Library | OpenShotAudio 0.4.0

Loading...
Searching...
No Matches
juce_ZipFile.cpp
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
23 namespace juce
24{
25
26 inline uint16 readUnalignedLittleEndianShort (const void* buffer)
27{
28 auto data = readUnaligned<uint16> (buffer);
29 return ByteOrder::littleEndianShort (&data);
30}
31
32 inline uint32 readUnalignedLittleEndianInt (const void* buffer)
33{
34 auto data = readUnaligned<uint32> (buffer);
35 return ByteOrder::littleEndianInt (&data);
36}
37
38 struct ZipFile::ZipEntryHolder
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//==============================================================================
74 static 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
125 static 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//==============================================================================
139 struct ZipFile::ZipInputStream final : public InputStream
140{
141 ZipInputStream (ZipFile& zf, const ZipFile::ZipEntryHolder& zei)
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
178 int64 getTotalLength() override
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
216 int64 getPosition() override
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
227 private:
228 ZipFile& file;
229 ZipEntryHolder zipEntryHolder;
230 int64 pos = 0;
231 int headerSize = 0;
232 InputStream* inputStream;
233 std::unique_ptr<InputStream> streamToDelete;
234
235 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ZipInputStream)
236};
237
238
239//==============================================================================
240 ZipFile::ZipFile (InputStream* stream, bool deleteStreamWhenDestroyed)
241 : inputStream (stream)
242{
243 if (deleteStreamWhenDestroyed)
244 streamToDelete.reset (inputStream);
245
246 init();
247}
248
249 ZipFile::ZipFile (InputStream& stream) : inputStream (&stream)
250{
251 init();
252}
253
254 ZipFile::ZipFile (const File& file) : inputSource (new FileInputSource (file))
255{
256 init();
257}
258
259 ZipFile::ZipFile (InputSource* source) : inputSource (source)
260{
261 init();
262}
263
264 ZipFile::~ZipFile()
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//==============================================================================
282 int ZipFile::getNumEntries() const noexcept
283{
284 return entries.size();
285}
286
287 const 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
295 int 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)
302 : entryFilename == fileName)
303 return i;
304 }
305
306 return -1;
307}
308
309 const ZipFile::ZipEntry* ZipFile::getEntry (const String& fileName, bool ignoreCase) const noexcept
310{
311 return getEntry (getIndexOfFileName (fileName, ignoreCase));
312}
313
314 InputStream* ZipFile::createStreamForEntry (const int index)
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
336 InputStream* ZipFile::createStreamForEntry (const ZipEntry& entry)
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
345 void ZipFile::sortEntriesByFilename()
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//==============================================================================
352 void ZipFile::init()
353{
354 std::unique_ptr<InputStream> toDelete;
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
372 in->setPosition (centralDirectoryPos);
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
401 Result ZipFile::uncompressTo (const File& targetDirectory,
402 const bool shouldOverwriteFiles)
403{
404 for (int i = 0; i < entries.size(); ++i)
405 {
406 auto result = uncompressEntry (i, targetDirectory, shouldOverwriteFiles);
407
408 if (result.failed())
409 return result;
410 }
411
412 return Result::ok();
413}
414
415 Result ZipFile::uncompressEntry (int index, const File& targetDirectory, bool shouldOverwriteFiles)
416{
417 return uncompressEntry (index,
418 targetDirectory,
419 shouldOverwriteFiles ? OverwriteFiles::yes : OverwriteFiles::no,
420 FollowSymlinks::no);
421}
422
423 Result 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
444 std::unique_ptr<InputStream> in (createStreamForEntry (index));
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//==============================================================================
491 struct ZipFile::Builder::Item
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 {
505 auto relativePath = file.getNativeLinkedTarget().replaceCharacter (File::getSeparatorChar(), L'/');
506
507 uncompressedSize = relativePath.length();
508
509 checksum = zlibNamespace::crc32 (0, (uint8_t*) relativePath.toRawUTF8(), (unsigned int) uncompressedSize);
510 compressedData << relativePath;
511 }
512 else if (compressionLevel > 0)
513 {
514 GZIPCompressorOutputStream compressor (compressedData, compressionLevel,
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
531 << compressedData;
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
551 private:
552 const File file;
553 std::unique_ptr<InputStream> stream;
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
611 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Item)
612};
613
614//==============================================================================
615 ZipFile::Builder::Builder() {}
616 ZipFile::Builder::~Builder() {}
617
618 void 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,
622 file.getLastModificationTime()));
623}
624
625 void 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
632 bool 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
673 struct 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;
682 HashMap<String, MemoryBlock> blocks;
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
767 static ZIPTests zipTests;
768
769#endif
770
771} // namespace juce
juce::BufferedInputStream
Definition juce_BufferedInputStream.h:37
juce::ByteOrder::littleEndianInt
static constexpr uint32 littleEndianInt(const void *bytes) noexcept
Definition juce_ByteOrder.h:199
juce::ByteOrder::littleEndianShort
static constexpr uint16 littleEndianShort(const void *bytes) noexcept
Definition juce_ByteOrder.h:198
juce::FileInputSource
Definition juce_FileInputSource.h:35
juce::FileOutputStream
Definition juce_FileOutputStream.h:35
juce::FileOutputStream::failedToOpen
bool failedToOpen() const noexcept
Definition juce_FileOutputStream.h:86
juce::File
Definition juce_File.h:45
juce::File::isSymbolicLink
bool isSymbolicLink() const
juce::File::getLastModificationTime
Time getLastModificationTime() const
Definition juce_File.cpp:538
juce::File::getSize
int64 getSize() const
juce::File::getFileName
String getFileName() const
Definition juce_File.cpp:372
juce::File::getChildFile
File getChildFile(StringRef relativeOrAbsolutePath) const
Definition juce_File.cpp:420
juce::File::createSymbolicLink
bool createSymbolicLink(const File &linkFileToCreate, bool overwriteExisting) const
Definition juce_File.cpp:1002
juce::File::getSeparatorChar
static juce_wchar getSeparatorChar()
juce::File::getParentDirectory
File getParentDirectory() const
Definition juce_File.cpp:358
juce::File::getNativeLinkedTarget
String getNativeLinkedTarget() const
juce::File::exists
bool exists() const
juce::GZIPDecompressorInputStream
Definition juce_GZIPDecompressorInputStream.h:39
juce::HashMap
Definition juce_HashMap.h:104
juce::HashMap::getReference
ValueType & getReference(KeyTypeParameter keyToLookFor)
Definition juce_HashMap.h:185
juce::InputSource
Definition juce_InputSource.h:38
juce::InputStream
Definition juce_InputStream.h:37
juce::InputStream::setPosition
virtual bool setPosition(int64 newPosition)=0
juce::InputStream::getTotalLength
virtual int64 getTotalLength()=0
juce::InputStream::readIntoMemoryBlock
virtual size_t readIntoMemoryBlock(MemoryBlock &destBlock, ssize_t maxNumBytesToRead=-1)
Definition juce_InputStream.cpp:223
juce::InputStream::read
virtual int read(void *destBuffer, int maxBytesToRead)=0
juce::MemoryBlock
Definition juce_MemoryBlock.h:33
juce::MemoryInputStream
Definition juce_MemoryInputStream.h:36
juce::MemoryOutputStream
Definition juce_MemoryOutputStream.h:36
juce::OutputStream
Definition juce_OutputStream.h:38
juce::OutputStream::getPosition
virtual int64 getPosition()=0
juce::OutputStream::writeShort
virtual bool writeShort(short value)
Definition juce_OutputStream.cpp:97
juce::OutputStream::writeInt
virtual bool writeInt(int value)
Definition juce_OutputStream.cpp:109
juce::OwnedArray::size
int size() const noexcept
Definition juce_OwnedArray.h:129
juce::OwnedArray::getUnchecked
ObjectClass * getUnchecked(int index) const noexcept
Definition juce_OwnedArray.h:159
juce::OwnedArray::clear
void clear(bool deleteObjects=true)
Definition juce_OwnedArray.h:106
juce::OwnedArray::add
ObjectClass * add(ObjectClass *newObject)
Definition juce_OwnedArray.h:293
juce::OwnedArray::begin
ObjectClass ** begin() noexcept
Definition juce_OwnedArray.h:200
juce::OwnedArray::end
ObjectClass ** end() noexcept
Definition juce_OwnedArray.h:216
juce::Result
Definition juce_Result.h:57
juce::Result::fail
static Result fail(const String &errorMessage) noexcept
Definition juce_Result.cpp:65
juce::Result::ok
static Result ok() noexcept
Definition juce_Result.h:61
juce::StringArray
Definition juce_StringArray.h:35
juce::String
Definition juce_String.h:53
juce::String::isEmpty
bool isEmpty() const noexcept
Definition juce_String.h:310
juce::String::replaceCharacter
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Definition juce_String.cpp:1344
juce::String::fromUTF8
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition juce_String.cpp:2125
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Definition juce_String.h:316
juce::Time
Definition juce_Time.h:37
juce::UnitTest
Definition juce_UnitTest.h:70
juce::ZipFile::Builder
Definition juce_ZipFile.h:209
juce::ZipFile::Builder::Builder
Builder()
Definition juce_ZipFile.cpp:615
juce::ZipFile::Builder::addEntry
void addEntry(InputStream *streamToRead, int compressionLevel, const String &storedPathName, Time fileModificationTime)
Definition juce_ZipFile.cpp:625
juce::ZipFile::Builder::writeToStream
bool writeToStream(OutputStream &target, double *progress) const
Definition juce_ZipFile.cpp:632
juce::ZipFile::Builder::addFile
void addFile(const File &fileToAdd, int compressionLevel, const String &storedPathName=String())
Definition juce_ZipFile.cpp:618
juce::ZipFile::Builder::~Builder
~Builder()
Definition juce_ZipFile.cpp:616
juce::ZipFile::uncompressTo
Result uncompressTo(const File &targetDirectory, bool shouldOverwriteFiles=true)
Definition juce_ZipFile.cpp:401
juce::ZipFile::createStreamForEntry
InputStream * createStreamForEntry(int index)
Definition juce_ZipFile.cpp:314
juce::ZipFile::getEntry
const ZipEntry * getEntry(int index) const noexcept
Definition juce_ZipFile.cpp:287
juce::ZipFile::~ZipFile
~ZipFile()
Definition juce_ZipFile.cpp:264
juce::ZipFile::getNumEntries
int getNumEntries() const noexcept
Definition juce_ZipFile.cpp:282
juce::ZipFile::ZipEntry::filename
String filename
Definition juce_ZipFile.h:75
juce::ZipFile::ZipEntry::uncompressedSize
int64 uncompressedSize
Definition juce_ZipFile.h:78
juce::ZipFile::ZipFile
ZipFile(const File &file)
Definition juce_ZipFile.cpp:254
juce::ZipFile::ZipEntry::externalFileAttributes
uint32 externalFileAttributes
Definition juce_ZipFile.h:90
juce::ZipFile::ZipEntry::isSymbolicLink
bool isSymbolicLink
Definition juce_ZipFile.h:84
juce::ZipFile::uncompressEntry
Result uncompressEntry(int index, const File &targetDirectory, bool shouldOverwriteFiles=true)
Definition juce_ZipFile.cpp:415
juce::ZipFile::getIndexOfFileName
int getIndexOfFileName(const String &fileName, bool ignoreCase=false) const noexcept
Definition juce_ZipFile.cpp:295
juce::ZipFile::sortEntriesByFilename
void sortEntriesByFilename()
Definition juce_ZipFile.cpp:345
juce::ZipFile::ZipEntry::fileTime
Time fileTime
Definition juce_ZipFile.h:81
juce::ZipFile::ZipEntry
Definition juce_ZipFile.h:73