Skip to content

File PackageFileSystem.h

File List > Amplitude > IO > PackageFileSystem.h

Go to the documentation of this file

// Copyright (c) 2024-present Sparky Studios. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#ifndef _AM_IO_PACKAGE_FILESYSTEM_H
#define _AM_IO_PACKAGE_FILESYSTEM_H

#include <SparkyStudios/Audio/Amplitude/Core/Memory.h>
#include <SparkyStudios/Audio/Amplitude/Core/Thread.h>
#include <SparkyStudios/Audio/Amplitude/IO/FileSystem.h>

namespace SparkyStudios::Audio::Amplitude
{
    enum ePackageFileCompressionMode : AmUInt8
    {
        ePackageFileCompressionMode_Uncompressed,

        ePackageFileCompressionMode_Compressed,

        ePackageFileCompressionMode_Invalid
    };

    struct PackageFileCompressedChunk
    {
        AmSize m_Offset = 0;

        AmSize m_Size = 0;

        AmSize m_CompressedSize = 0;
    };

    struct PackageFileItemDescription
    {
        AmString m_Name;

        AmSize m_Offset = 0;

        AmSize m_Size = 0;

        AmSize m_CompressedBlockSize = 0;

        std::vector<PackageFileCompressedChunk> m_CompressedChunks;
    };

    struct PackageFileHeaderDescription
    {
        AmUInt8 m_Header[4] = { 'A', 'M', 'P', 'K' };

        AmUInt16 m_Version = 0;

        ePackageFileCompressionMode m_CompressionMode = ePackageFileCompressionMode_Invalid;

        std::vector<PackageFileItemDescription> m_Items;
    };

    class AM_API_PUBLIC PackageFileSystem final : public FileSystem
    {
    public:
        PackageFileSystem();

        ~PackageFileSystem() override;

        void SetBasePath(const AmOsString& basePath) override;

        [[nodiscard]] const AmOsString& GetBasePath() const override;

        [[nodiscard]] AmOsString ResolvePath(const AmOsString& path) const override;

        [[nodiscard]] bool Exists(const AmOsString& path) const override;

        [[nodiscard]] bool IsDirectory(const AmOsString& path) const override;

        [[nodiscard]] AmOsString Join(const std::vector<AmOsString>& parts) const override;

        [[nodiscard]] std::shared_ptr<File> OpenFile(const AmOsString& path, eFileOpenMode mode = eFileOpenMode_Read) const override;

        void StartOpenFileSystem() override;

        bool TryFinalizeOpenFileSystem() override;

        void StartCloseFileSystem() override;

        bool TryFinalizeCloseFileSystem() override;

        template<class TFileSystem, class... Args>
        void SetPlatformFileSystem(Args&&... args)
        {
            static_assert(std::is_base_of_v<FileSystem, TFileSystem>, "T must inherit from FileSystem");
            static_assert(!std::is_same_v<TFileSystem, PackageFileSystem>, "T cannot be PackageFileSystem");

            // If the package file is already loaded, this method is a noop
            if (IsValid())
                return;

            _fileSystem.reset(ampoolnew(eMemoryPoolKind_IO, TFileSystem, std::forward<Args>(args)...));
        }

        void SetPlatformFileSystem(std::shared_ptr<FileSystem> fileSystem);

        [[nodiscard]] bool IsValid() const;

    private:
        static void LoadPackage(AmVoidPtr pParam);

        std::shared_ptr<FileSystem> _fileSystem;

        AmOsString _packagePath;
        std::shared_ptr<File> _packageFile;

        AmThreadHandle _loadingThreadHandle;
        mutable bool _initialized;
        bool _valid;

        PackageFileHeaderDescription _header;
        AmSize _headerSize;
    };
} // namespace SparkyStudios::Audio::Amplitude

#endif // _AM_IO_PACKAGE_FILESYSTEM_H