//
// Copyright 2006 The Android Open Source Project
//
// Build resource files from raw assets.
//

#ifndef RESOURCE_TABLE_H
#define RESOURCE_TABLE_H

#include <map>
#include <queue>
#include <set>

#include "ConfigDescription.h"
#include "ResourceFilter.h"
#include "SourcePos.h"
#include "StringPool.h"
#include "Symbol.h"

class XMLNode;
class ResourceTable;

enum {
    XML_COMPILE_STRIP_COMMENTS = 1<<0,
    XML_COMPILE_ASSIGN_ATTRIBUTE_IDS = 1<<1,
    XML_COMPILE_PARSE_VALUES = 1 << 2,
    XML_COMPILE_COMPACT_WHITESPACE = 1<<3,
    XML_COMPILE_STRIP_WHITESPACE = 1<<4,
    XML_COMPILE_STRIP_RAW_VALUES = 1<<5,
    XML_COMPILE_UTF8 = 1<<6,

    XML_COMPILE_STANDARD_RESOURCE =
            XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS | XML_COMPILE_PARSE_VALUES
            | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
};

status_t compileXmlFile(const Bundle* bundle,
                        const sp<AaptAssets>& assets,
                        const String16& resourceName,
                        const sp<AaptFile>& target,
                        ResourceTable* table,
                        int options = XML_COMPILE_STANDARD_RESOURCE);

status_t compileXmlFile(const Bundle* bundle,
                        const sp<AaptAssets>& assets,
                        const String16& resourceName,
                        const sp<AaptFile>& target,
                        const sp<AaptFile>& outTarget,
                        ResourceTable* table,
                        int options = XML_COMPILE_STANDARD_RESOURCE);

status_t compileXmlFile(const Bundle* bundle,
                        const sp<AaptAssets>& assets,
                        const String16& resourceName,
                        const sp<XMLNode>& xmlTree,
                        const sp<AaptFile>& target,
                        ResourceTable* table,
                        int options = XML_COMPILE_STANDARD_RESOURCE);

status_t compileResourceFile(Bundle* bundle,
                             const sp<AaptAssets>& assets,
                             const sp<AaptFile>& in,
                             const ResTable_config& defParams,
                             const bool overwrite,
                             ResourceTable* outTable);

struct AccessorCookie
{
    SourcePos sourcePos;
    String8 attr;
    String8 value;

    AccessorCookie(const SourcePos&p, const String8& a, const String8& v)
        :sourcePos(p),
         attr(a),
         value(v)
    {
    }
};

// Holds the necessary information to compile the
// resource.
struct CompileResourceWorkItem {
    String16 resourceName;
    String8 resPath;
    sp<AaptFile> file;
    sp<XMLNode> xmlRoot;
    bool needsCompiling = true;
};

class ResourceTable : public ResTable::Accessor
{
public:
    // The type of package to build.
    enum PackageType {
        App,
        System,
        SharedLibrary,
        AppFeature
    };

    class Package;
    class Type;
    class Entry;
    class ConfigList;

    /**
     * Exposed for testing. Determines whether a versioned resource should be generated
     * based on the other available configurations for that resource.
     */
    static bool shouldGenerateVersionedResource(const sp<ConfigList>& configList,
                                                const ConfigDescription& sourceConfig,
                                                const int sdkVersionToGenerate);

    ResourceTable(Bundle* bundle, const String16& assetsPackage, PackageType type);

    const String16& getAssetsPackage() const {
        return mAssetsPackage;
    }

    /**
     * Returns the queue of resources that need to be compiled.
     * This is only used for resources that have been generated
     * during the compilation phase. If they were just added
     * to the AaptAssets, then they may be skipped over
     * and would mess up iteration order for the existing
     * resources.
     */
    std::queue<CompileResourceWorkItem>& getWorkQueue() {
        return mWorkQueue;
    }

    status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);

    status_t addPublic(const SourcePos& pos,
                       const String16& package,
                       const String16& type,
                       const String16& name,
                       const uint32_t ident);

    status_t addEntry(const SourcePos& pos,
                      const String16& package,
                      const String16& type,
                      const String16& name,
                      const String16& value,
                      const Vector<StringPool::entry_style_span>* style = NULL,
                      const ResTable_config* params = NULL,
                      const bool doSetIndex = false,
                      const int32_t format = ResTable_map::TYPE_ANY,
                      const bool overwrite = false);

    status_t startBag(const SourcePos& pos,
                    const String16& package,
                    const String16& type,
                    const String16& name,
                    const String16& bagParent,
                    const ResTable_config* params = NULL,
                    bool overlay = false,
                    bool replace = false,
                    bool isId = false);
    
    status_t addBag(const SourcePos& pos,
                    const String16& package,
                    const String16& type,
                    const String16& name,
                    const String16& bagParent,
                    const String16& bagKey,
                    const String16& value,
                    const Vector<StringPool::entry_style_span>* style = NULL,
                    const ResTable_config* params = NULL,
                    bool replace = false,
                    bool isId = false,
                    const int32_t format = ResTable_map::TYPE_ANY);

    bool hasBagOrEntry(const String16& package,
                       const String16& type,
                       const String16& name) const;

    bool hasBagOrEntry(const String16& package,
                       const String16& type,
                       const String16& name,
                       const ResTable_config& config) const;

    bool hasBagOrEntry(const String16& ref,
                       const String16* defType = NULL,
                       const String16* defPackage = NULL);

    bool appendComment(const String16& package,
                       const String16& type,
                       const String16& name,
                       const String16& comment,
                       bool onlyIfEmpty = false);

    bool appendTypeComment(const String16& package,
                           const String16& type,
                           const String16& name,
                           const String16& comment);
    
    void canAddEntry(const SourcePos& pos,
        const String16& package, const String16& type, const String16& name);
        
    size_t size() const;
    size_t numLocalResources() const;
    bool hasResources() const;

    status_t modifyForCompat(const Bundle* bundle);
    status_t modifyForCompat(const Bundle* bundle,
                             const String16& resourceName,
                             const sp<AaptFile>& file,
                             const sp<XMLNode>& root);

    status_t processBundleFormat(const Bundle* bundle,
                                 const String16& resourceName,
                                 const sp<AaptFile>& file,
                                 const sp<XMLNode>& parent);


    sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
            const bool isBase);

    static inline uint32_t makeResId(uint32_t packageId,
                                     uint32_t typeId,
                                     uint32_t nameId)
    {
        return nameId | (typeId<<16) | (packageId<<24);
    }

    static inline uint32_t getResId(const sp<Package>& p,
                                    const sp<Type>& t,
                                    uint32_t nameId);

    uint32_t getResId(const String16& package,
                      const String16& type,
                      const String16& name,
                      bool onlyPublic = true) const;

    uint32_t getResId(const String16& ref,
                      const String16* defType = NULL,
                      const String16* defPackage = NULL,
                      const char** outErrorMsg = NULL,
                      bool onlyPublic = true) const;

    static bool isValidResourceName(const String16& s);
    
    bool stringToValue(Res_value* outValue, StringPool* pool,
                       const String16& str,
                       bool preserveSpaces, bool coerceType,
                       uint32_t attrID,
                       const Vector<StringPool::entry_style_span>* style = NULL,
                       String16* outStr = NULL, void* accessorCookie = NULL,
                       uint32_t attrType = ResTable_map::TYPE_ANY,
                       const String8* configTypeName = NULL,
                       const ConfigDescription* config = NULL);

    status_t assignResourceIds();
    status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL,
                        bool skipSymbolsWithoutDefaultLocalization = false);
    void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
    void addDefaultLocalization(const String16& name);
    status_t validateLocalizations(void);

    status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
            const sp<AaptFile>& dest, const bool isBase);
    status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);

    void writePublicDefinitions(const String16& package, FILE* fp);

    virtual uint32_t getCustomResource(const String16& package,
                                       const String16& type,
                                       const String16& name) const;
    virtual uint32_t getCustomResourceWithCreation(const String16& package,
                                                   const String16& type,
                                                   const String16& name,
                                                   const bool createIfNeeded);
    virtual uint32_t getRemappedPackage(uint32_t origPackage) const;
    virtual bool getAttributeType(uint32_t attrID, uint32_t* outType);
    virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin);
    virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax);
    virtual bool getAttributeKeys(uint32_t attrID, Vector<String16>* outKeys);
    virtual bool getAttributeEnum(uint32_t attrID,
                                  const char16_t* name, size_t nameLen,
                                  Res_value* outValue);
    virtual bool getAttributeFlags(uint32_t attrID,
                                   const char16_t* name, size_t nameLen,
                                   Res_value* outValue);
    virtual uint32_t getAttributeL10N(uint32_t attrID);

    virtual bool getLocalizationSetting();
    virtual void reportError(void* accessorCookie, const char* fmt, ...);

    void setCurrentXmlPos(const SourcePos& pos) { mCurrentXmlPos = pos; }

    class Item {
    public:
        Item() : isId(false), format(ResTable_map::TYPE_ANY), bagKeyId(0), evaluating(false)
            { memset(&parsedValue, 0, sizeof(parsedValue)); }
        Item(const SourcePos& pos,
             bool _isId,
             const String16& _value,
             const Vector<StringPool::entry_style_span>* _style = NULL,
             int32_t format = ResTable_map::TYPE_ANY);
        Item(const Item& o) : sourcePos(o.sourcePos),
            isId(o.isId), value(o.value), style(o.style),
            format(o.format), bagKeyId(o.bagKeyId), evaluating(false) {
            memset(&parsedValue, 0, sizeof(parsedValue));
        }
        ~Item() { }

        Item& operator=(const Item& o) {
            sourcePos = o.sourcePos;
            isId = o.isId;
            value = o.value;
            style = o.style;
            format = o.format;
            bagKeyId = o.bagKeyId;
            parsedValue = o.parsedValue;
            return *this;
        }

        SourcePos                               sourcePos;
        mutable bool                            isId;
        String16                                value;
        Vector<StringPool::entry_style_span>    style;
        int32_t                                 format;
        uint32_t                                bagKeyId;
        mutable bool                            evaluating;
        Res_value                               parsedValue;
    };

    class Entry : public RefBase {
    public:
        Entry(const String16& name, const SourcePos& pos)
            : mName(name), mType(TYPE_UNKNOWN),
              mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos)
        { }

        Entry(const Entry& entry);
        Entry& operator=(const Entry& entry);

        virtual ~Entry() { }

        enum type {
            TYPE_UNKNOWN = 0,
            TYPE_ITEM,
            TYPE_BAG
        };
        
        String16 getName() const { return mName; }
        type getType() const { return mType; }

        void setParent(const String16& parent) { mParent = parent; }
        String16 getParent() const { return mParent; }

        status_t makeItABag(const SourcePos& sourcePos);

        status_t emptyBag(const SourcePos& sourcePos);
 
        status_t setItem(const SourcePos& pos,
                         const String16& value,
                         const Vector<StringPool::entry_style_span>* style = NULL,
                         int32_t format = ResTable_map::TYPE_ANY,
                         const bool overwrite = false);

        status_t addToBag(const SourcePos& pos,
                          const String16& key, const String16& value,
                          const Vector<StringPool::entry_style_span>* style = NULL,
                          bool replace=false, bool isId = false,
                          int32_t format = ResTable_map::TYPE_ANY);

        status_t removeFromBag(const String16& key);

        // Index of the entry's name string in the key pool.
        int32_t getNameIndex() const { return mNameIndex; }
        void setNameIndex(int32_t index) { mNameIndex = index; }

        const Item* getItem() const { return mType == TYPE_ITEM ? &mItem : NULL; }
        const KeyedVector<String16, Item>& getBag() const { return mBag; }

        status_t generateAttributes(ResourceTable* table,
                                    const String16& package);

        status_t assignResourceIds(ResourceTable* table,
                                   const String16& package);

        status_t prepareFlatten(StringPool* strings, ResourceTable* table,
               const String8* configTypeName, const ConfigDescription* config);

        status_t remapStringValue(StringPool* strings);

        ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);

        const SourcePos& getPos() const { return mPos; }

    private:
        String16 mName;
        String16 mParent;
        type mType;
        Item mItem;
        int32_t mItemFormat;
        KeyedVector<String16, Item> mBag;
        int32_t mNameIndex;
        uint32_t mParentId;
        SourcePos mPos;
    };
    
    class ConfigList : public RefBase {
    public:
        ConfigList(const String16& name, const SourcePos& pos)
            : mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { }
        virtual ~ConfigList() { }
        
        String16 getName() const { return mName; }
        const SourcePos& getPos() const { return mPos; }
        
        void appendComment(const String16& comment, bool onlyIfEmpty = false);
        const String16& getComment() const { return mComment; }
        
        void appendTypeComment(const String16& comment);
        const String16& getTypeComment() const { return mTypeComment; }
        
        // Index of this entry in its Type.
        int32_t getEntryIndex() const { return mEntryIndex; }
        void setEntryIndex(int32_t index) { mEntryIndex = index; }
        
        void setPublic(bool pub) { mPublic = pub; }
        bool getPublic() const { return mPublic; }
        void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; }
        const SourcePos& getPublicSourcePos() { return mPublicSourcePos; }
        
        void addEntry(const ResTable_config& config, const sp<Entry>& entry) {
            mEntries.add(config, entry);
        }
        
        const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
    private:
        const String16 mName;
        const SourcePos mPos;
        String16 mComment;
        String16 mTypeComment;
        bool mPublic;
        SourcePos mPublicSourcePos;
        int32_t mEntryIndex;
        DefaultKeyedVector<ConfigDescription, sp<Entry> > mEntries;
    };
    
    class Public {
    public:
        Public() : sourcePos(), ident(0) { }
        Public(const SourcePos& pos,
               const String16& _comment,
               uint32_t _ident)
            : sourcePos(pos),
            comment(_comment), ident(_ident) { }
        Public(const Public& o) : sourcePos(o.sourcePos),
            comment(o.comment), ident(o.ident) { }
        ~Public() { }
        
        Public& operator=(const Public& o) {
            sourcePos = o.sourcePos;
            comment = o.comment;
            ident = o.ident;
            return *this;
        }
        
        SourcePos   sourcePos;
        String16    comment;
        uint32_t    ident;
    };
    
    class Type : public RefBase {
    public:
        Type(const String16& name, const SourcePos& pos)
                : mName(name), mFirstPublicSourcePos(NULL), mPublicIndex(-1), mIndex(-1), mPos(pos)
        { }
        virtual ~Type() { delete mFirstPublicSourcePos; }

        status_t addPublic(const SourcePos& pos,
                           const String16& name,
                           const uint32_t ident);
                           
        void canAddEntry(const String16& name);
        
        String16 getName() const { return mName; }
        sp<Entry> getEntry(const String16& entry,
                           const SourcePos& pos,
                           const ResTable_config* config = NULL,
                           bool doSetIndex = false,
                           bool overlay = false,
                           bool autoAddOverlay = false);

        bool isPublic(const String16& entry) const {
            return mPublic.indexOfKey(entry) >= 0;
        }

        sp<ConfigList> removeEntry(const String16& entry);

        SortedVector<ConfigDescription> getUniqueConfigs() const;

        const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }

        int32_t getPublicIndex() const { return mPublicIndex; }

        int32_t getIndex() const { return mIndex; }
        void setIndex(int32_t index) { mIndex = index; }

        status_t applyPublicEntryOrder();

        const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
        const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
        const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
        
        const SourcePos& getPos() const { return mPos; }

    private:
        String16 mName;
        SourcePos* mFirstPublicSourcePos;
        DefaultKeyedVector<String16, Public> mPublic;
        DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
        Vector<sp<ConfigList> > mOrderedConfigs;
        SortedVector<String16> mCanAddEntries;
        int32_t mPublicIndex;
        int32_t mIndex;
        SourcePos mPos;
    };

    class Package : public RefBase {
    public:
        Package(const String16& name, size_t packageId);
        virtual ~Package() { }

        String16 getName() const { return mName; }
        sp<Type> getType(const String16& type,
                         const SourcePos& pos,
                         bool doSetIndex = false);

        size_t getAssignedId() const { return mPackageId; }

        const ResStringPool& getTypeStrings() const { return mTypeStrings; }
        uint32_t indexOfTypeString(const String16& s) const { return mTypeStringsMapping.valueFor(s); }
        const sp<AaptFile> getTypeStringsData() const { return mTypeStringsData; }
        status_t setTypeStrings(const sp<AaptFile>& data);

        const ResStringPool& getKeyStrings() const { return mKeyStrings; }
        uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); }
        const sp<AaptFile> getKeyStringsData() const { return mKeyStringsData; }
        status_t setKeyStrings(const sp<AaptFile>& data);

        status_t applyPublicTypeOrder();

        const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; }
        const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; }

        void movePrivateAttrs();

    private:
        status_t setStrings(const sp<AaptFile>& data,
                            ResStringPool* strings,
                            DefaultKeyedVector<String16, uint32_t>* mappings);

        const String16 mName;
        const size_t mPackageId;
        DefaultKeyedVector<String16, sp<Type> > mTypes;
        Vector<sp<Type> > mOrderedTypes;
        sp<AaptFile> mTypeStringsData;
        sp<AaptFile> mKeyStringsData;
        ResStringPool mTypeStrings;
        ResStringPool mKeyStrings;
        DefaultKeyedVector<String16, uint32_t> mTypeStringsMapping;
        DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping;
    };

    void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);

    /**
     * Make an attribute with the specified format. If another attribute with the same name but
     * different format exists, this method returns false. If the name is not taken, or if the
     * format is identical, this returns true.
     */
    bool makeAttribute(const String16& package,
                       const String16& name,
                       const SourcePos& source,
                       int32_t format,
                       const String16& comment,
                       bool appendComment);

private:
    void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
    sp<Package> getPackage(const String16& package);
    sp<Type> getType(const String16& package,
                     const String16& type,
                     const SourcePos& pos,
                     bool doSetIndex = false);
    sp<Entry> getEntry(const String16& package,
                       const String16& type,
                       const String16& name,
                       const SourcePos& pos,
                       bool overlay,
                       const ResTable_config* config = NULL,
                       bool doSetIndex = false);
    sp<const Entry> getEntry(uint32_t resID,
                             const ResTable_config* config = NULL) const;
    sp<ConfigList> getConfigList(const String16& package,
                                 const String16& type,
                                 const String16& name) const;
    const Item* getItem(uint32_t resID, uint32_t attrID) const;
    bool getItemValue(uint32_t resID, uint32_t attrID,
                      Res_value* outValue);
    int getPublicAttributeSdkLevel(uint32_t attrId) const;

    status_t processBundleFormatImpl(const Bundle* bundle,
                                     const String16& resourceName,
                                     const sp<AaptFile>& file,
                                     const sp<XMLNode>& parent,
                                     Vector<sp<XMLNode> >* namespaces);

    String16 mAssetsPackage;
    PackageType mPackageType;
    sp<AaptAssets> mAssets;
    uint32_t mTypeIdOffset;
    DefaultKeyedVector<String16, sp<Package> > mPackages;
    Vector<sp<Package> > mOrderedPackages;
    size_t mNumLocal;
    SourcePos mCurrentXmlPos;
    Bundle* mBundle;

    // key = string resource name, value = set of locales in which that name is defined
    std::map<String16, std::map<String8, SourcePos>> mLocalizations;
    // set of string resources names that have a default localization
    std::set<String16> mHasDefaultLocalization;
    std::queue<CompileResourceWorkItem> mWorkQueue;
};

#endif
