summaryrefslogtreecommitdiff
path: root/indra/newview/rlvhelper.h
blob: f2413325941891638f302fcd6a11e5ed824483e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/**
 * @file rlvhelper.h
 * @author Kitty Barnett
 * @brief RLVa helper classes for internal use only
 *
 * $LicenseInfo:firstyear=2024&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2024, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#pragma once

#include "rlvdefines.h"

// ============================================================================
// Forward declarations
//

class RlvCommand;

// ============================================================================

namespace Rlv
{
    // ============================================================================
    // BehaviourInfo class - Generic behaviour descriptor (used by restrictions, reply and force commands)
    //

    class BehaviourInfo
    {
    public:
        enum EBehaviourFlags : uint32_t
        {
            // General behaviour flags
            Strict = 0x0001,				// Behaviour has a "_sec" version
            Synonym = 0x0002,				// Behaviour is a synonym of another
            Extended = 0x0004,				// Behaviour is part of the RLVa extended command set
            Experimental = 0x0008,			// Behaviour is part of the RLVa experimental command set
            Blocked = 0x0010,				// Behaviour is blocked
            Deprecated = 0x0020,			// Behaviour is deprecated
            MaskGeneral = 0x0FFF,

            // Force-wear specific flags
            ForceWear_WearReplace = 0x0001 << 16,
            ForceWear_WearAdd = 0x0002 << 16,
            ForceWear_WearRemove = 0x0004 << 16,
            ForceWear_Node = 0x0010 << 16,
            ForceWear_Subtree = 0x0020 << 16,
            ForceWear_ContextNone = 0x0100 << 16,
            ForceWear_ContextObject = 0x0200 << 16,
            MaskForceWear = 0xFFFFu << 16
        };

        BehaviourInfo(const std::string& strBhvr, EBehaviour eBhvr, EParamType maskParamType, std::underlying_type_t<EBehaviourFlags> nBhvrFlags = 0)
            : mBhvr(strBhvr), mBhvrType(eBhvr), mBhvrFlags(nBhvrFlags), mMaskParamType(to_underlying(maskParamType)) {}
        virtual ~BehaviourInfo() {}

        const std::string&    getBehaviour() const { return mBhvr; }
        EBehaviour            getBehaviourType() const { return mBhvrType; }
        std::underlying_type_t<EBehaviourFlags> getBehaviourFlags() const { return mBhvrFlags; }
        std::underlying_type_t<EParamType> getParamTypeMask() const { return mMaskParamType; }
        bool                  hasStrict() const { return mBhvrFlags & Strict; }
        bool                  isBlocked() const { return mBhvrFlags & Blocked; }
        bool                  isExperimental() const { return mBhvrFlags & Experimental; }
        bool                  isExtended() const { return mBhvrFlags & Extended; }
        bool                  isSynonym() const { return mBhvrFlags & Synonym; }
        void                  toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable);

        virtual ECmdRet  processCommand(const RlvCommand& rlvCmd) const { return ECmdRet::FailedNoProcessor; }

    protected:
        std::string mBhvr;
        EBehaviour mBhvrType;
        std::underlying_type_t<EBehaviourFlags> mBhvrFlags;
        std::underlying_type_t<EParamType> mMaskParamType;
    };

    inline void BehaviourInfo::toggleBehaviourFlag(EBehaviourFlags eBhvrFlag, bool fEnable)
    {
        if (fEnable)
            mBhvrFlags |= eBhvrFlag;
        else
            mBhvrFlags &= ~eBhvrFlag;
    }

    // ============================================================================
    // BehaviourDictionary and related classes
    //

    class BehaviourDictionary : public LLSingleton<BehaviourDictionary>
    {
        LLSINGLETON(BehaviourDictionary);
    protected:
        ~BehaviourDictionary() override;
    public:
        void addEntry(const BehaviourInfo* entry_p);

        /*
         * General helper functions
         */
    public:
        EBehaviour           getBehaviourFromString(const std::string& strBhvr, EParamType eParamType, bool* is_strict_p = nullptr) const;
        const BehaviourInfo* getBehaviourInfo(EBehaviour eBhvr, EParamType eParamType) const;
        const BehaviourInfo* getBehaviourInfo(const std::string& strBhvr, EParamType eParamType, bool* is_strict_p = nullptr) const;
        bool                 getCommands(const std::string& strMatch, EParamType eParamType, std::list<std::string>& cmdList) const;
        bool                 getHasStrict(EBehaviour eBhvr) const;
        void                 toggleBehaviourFlag(const std::string& strBhvr, EParamType eParamType, BehaviourInfo::EBehaviourFlags eBvhrFlag, bool fEnable);

        /*
         * Member variables
         */
    protected:
        std::list<const BehaviourInfo*> mBhvrInfoList;
        std::map<std::pair<std::string, EParamType>, const BehaviourInfo*> mString2InfoMap;
        std::multimap<EBehaviour, const BehaviourInfo*> mBhvr2InfoMap;
    };

    // ============================================================================
    // CommandHandler and related classes
    //

    typedef ECmdRet(BhvrHandlerFunc)(const RlvCommand&, bool&);
    typedef void(BhvrToggleHandlerFunc)(EBehaviour, bool);
    typedef ECmdRet(ForceHandlerFunc)(const RlvCommand&);
    typedef ECmdRet(ReplyHandlerFunc)(const RlvCommand&, std::string&);

    //
    // CommandHandlerBaseImpl - Base implementation for each command type (the old process(AddRem|Force|Reply)Command functions)
    //
    template<EParamType paramType> struct CommandHandlerBaseImpl;
    template<> struct CommandHandlerBaseImpl<EParamType::AddRem> { static ECmdRet processCommand(const RlvCommand&, BhvrHandlerFunc*, BhvrToggleHandlerFunc* = nullptr); };
    template<> struct CommandHandlerBaseImpl<EParamType::Force>  { static ECmdRet processCommand(const RlvCommand&, ForceHandlerFunc*); };
    template<> struct CommandHandlerBaseImpl<EParamType::Reply>  { static ECmdRet processCommand(const RlvCommand&, ReplyHandlerFunc*); };

    //
    // CommandHandler - The actual command handler (Note that a handler is more general than a processor; a handler can - for instance - be used by multiple processors)
    //
    #if LL_WINDOWS
        #define RLV_TEMPL_FIX(x) template<x>
    #else
        #define RLV_TEMPL_FIX(x) template<typename Placeholder = int>
    #endif // LL_WINDOWS


    template <EParamType templParamType, EBehaviour templBhvr>
    struct CommandHandler
    {
        RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::AddRem>::type) static ECmdRet onCommand(const RlvCommand&, bool&);
        RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::AddRem>::type) static void onCommandToggle(EBehaviour, bool);
        RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::Force>::type)  static ECmdRet onCommand(const RlvCommand&);
        RLV_TEMPL_FIX(typename = typename std::enable_if<templParamType == EParamType::Reply>::type)  static ECmdRet onCommand(const RlvCommand&, std::string&);
    };

    // Aliases to improve readability in definitions
    template<EBehaviour templBhvr> using BehaviourHandler = CommandHandler<EParamType::AddRem, templBhvr>;
    template<EBehaviour templBhvr> using BehaviourToggleHandler = BehaviourHandler<templBhvr>;
    template<EBehaviour templBhvr> using ForceHandler = CommandHandler<EParamType::Force, templBhvr>;
    template<EBehaviour templBhvr> using ReplyHandler = CommandHandler<EParamType::Reply, templBhvr>;

    // List of shared handlers
    using VersionReplyHandler = ReplyHandler<EBehaviour::Version>;				// Shared between @version and @versionnew

    //
    // CommandProcessor - Templated glue class that brings BehaviourInfo, CommandHandlerBaseImpl and CommandHandler together
    //
    template <EParamType templParamType, EBehaviour templBhvr, typename handlerImpl = CommandHandler<templParamType, templBhvr>, typename baseImpl = CommandHandlerBaseImpl<templParamType>>
    class CommandProcessor : public BehaviourInfo
    {
    public:
        // Default constructor used by behaviour specializations
        RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr != EBehaviour::Unknown>::type)
        CommandProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, templBhvr, templParamType, nBhvrFlags) {}

        // Constructor used when we don't want to specialize on behaviour (see BehaviourGenericProcessor)
        RLV_TEMPL_FIX(typename = typename std::enable_if<templBhvr == EBehaviour::Unknown>::type)
        CommandProcessor(const std::string& strBhvr, EBehaviour eBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, eBhvr, templParamType, nBhvrFlags) {}

        ECmdRet processCommand(const RlvCommand& rlvCmd) const override { return baseImpl::processCommand(rlvCmd, &handlerImpl::onCommand); }
    };

    // Aliases to improve readability in definitions
    template<EBehaviour templBhvr, typename handlerImpl = CommandHandler<EParamType::AddRem, templBhvr>> using BehaviourProcessor = CommandProcessor<EParamType::AddRem, templBhvr, handlerImpl>;
    template<EBehaviour templBhvr, typename handlerImpl = CommandHandler<EParamType::Force, templBhvr>> using ForceProcessor = CommandProcessor<EParamType::Force, templBhvr, handlerImpl>;
    template<EBehaviour templBhvr, typename handlerImpl = CommandHandler<EParamType::Reply, templBhvr>> using ReplyProcessor = CommandProcessor<EParamType::Reply, templBhvr, handlerImpl>;

    // Provides pre-defined generic implementations of basic behaviours (template voodoo - see original commit for something that still made sense)
    template<EBehaviourOptionType templOptionType> struct BehaviourGenericHandler { static ECmdRet onCommand(const RlvCommand& rlvCmd, bool& fRefCount); };
    template<EBehaviourOptionType templOptionType> using BehaviourGenericProcessor = BehaviourProcessor<EBehaviour::Unknown, BehaviourGenericHandler<templOptionType>>;
    template<EBehaviourOptionType templOptionType> struct ForceGenericHandler { static ECmdRet onCommand(const RlvCommand& rlvCmd); };
    template<EBehaviourOptionType templOptionType> using ForceGenericProcessor = ForceProcessor<EBehaviour::Unknown, ForceGenericHandler<templOptionType>>;

    // ============================================================================
    // BehaviourProcessor and related classes - Handles add/rem comamnds aka "restrictions)
    //

    template <EBehaviour eBhvr, typename handlerImpl = BehaviourHandler<eBhvr>, typename toggleHandlerImpl = BehaviourToggleHandler<eBhvr>>
    class BehaviourToggleProcessor : public BehaviourInfo
    {
    public:
        BehaviourToggleProcessor(const std::string& strBhvr, U32 nBhvrFlags = 0) : BehaviourInfo(strBhvr, eBhvr, EParamType::AddRem, nBhvrFlags) {}
        ECmdRet processCommand(const RlvCommand& rlvCmd) const override { return CommandHandlerBaseImpl<EParamType::AddRem>::processCommand(rlvCmd, &handlerImpl::onCommand, &toggleHandlerImpl::onCommandToggle); }
    };
    template <EBehaviour eBhvr, EBehaviourOptionType optionType, typename toggleHandlerImpl = BehaviourToggleHandler<eBhvr>> using RlvBehaviourGenericToggleProcessor = BehaviourToggleProcessor<eBhvr, BehaviourGenericHandler<optionType>, toggleHandlerImpl>;

    // ============================================================================
    // Various helper classes/timers/functors
    //

    struct CommandDbgOut
    {
        CommandDbgOut(const std::string& orig_cmd, bool for_console) : mOrigCmd(orig_cmd), mForConsole(for_console) {}
        void add(std::string strCmd, ECmdRet eRet);
        std::string get() const;
        static std::string getDebugVerbFromReturnCode(ECmdRet eRet);
        static std::string getReturnCodeString(ECmdRet eRet);
    private:
        std::string mOrigCmd;
        std::map<ECmdRet, std::string> mCommandResults;
        bool mForConsole = false;
    };
}

// ============================================================================
// RlvCommand
//

class RlvCommand
{
public:
    explicit RlvCommand(const LLUUID& idObj, const std::string& strCmd);
    RlvCommand(const RlvCommand& rlvCmd, Rlv::EParamType eParamType = Rlv::EParamType::Unknown);

    /*
     * Member functions
     */
public:
    std::string        asString() const;
    const std::string& getBehaviour() const { return mBehaviour; }
    const Rlv::BehaviourInfo* getBehaviourInfo() const { return mBhvrInfo; }
    Rlv::EBehaviour    getBehaviourType() const { return (mBhvrInfo) ? mBhvrInfo->getBehaviourType() : Rlv::EBehaviour::Unknown; }
    U32                getBehaviourFlags() const { return (mBhvrInfo) ? mBhvrInfo->getBehaviourFlags() : 0; }
    const LLUUID&      getObjectID() const { return mObjId; }
    const std::string& getOption() const { return mOption; }
    const std::string& getParam() const { return mParam; }
    Rlv::EParamType    getParamType() const { return mParamType; }
    bool               hasOption() const { return !mOption.empty(); }
    bool               isBlocked() const { return (mBhvrInfo) ? mBhvrInfo->isBlocked() : false; }
    bool               isRefCounted() const { return mIsRefCounted; }
    bool               isStrict() const { return mIsStrict; }
    bool               isValid() const { return mIsValid; }
    Rlv::ECmdRet       processCommand() const { return (mBhvrInfo) ? mBhvrInfo->processCommand(*this) : Rlv::ECmdRet::FailedNoProcessor; }

protected:
    static bool parseCommand(const std::string& strCommand, std::string& strBehaviour, std::string& strOption, std::string& strParam);
    bool               markRefCounted() const { return mIsRefCounted = true; }

    /*
     * Operators
     */
public:
    bool operator ==(const RlvCommand&) const;

    /*
     * Member variables
     */
protected:
    bool                    mIsValid = false;
    LLUUID                  mObjId;
    std::string             mBehaviour;
    const Rlv::BehaviourInfo* mBhvrInfo = nullptr;
    Rlv::EParamType         mParamType = Rlv::EParamType::Unknown;
    bool                    mIsStrict = false;
    std::string             mOption;
    std::string             mParam;
    mutable bool            mIsRefCounted = false;

    friend class RlvHandler;
    friend class RlvObject;
    template<Rlv::EParamType> friend struct Rlv::CommandHandlerBaseImpl;
};

// ============================================================================