    001package net.minecraft.nbt;
    002
    003import java.io.DataInput;
    004import java.io.DataOutput;
    005import java.io.IOException;
    006import java.util.Collection;
    007import java.util.HashMap;
    008import java.util.Iterator;
    009import java.util.Map;
    010import net.minecraft.crash.CrashReport;
    011import net.minecraft.crash.CrashReportCategory;
    012import net.minecraft.util.ReportedException;
    013
    014public class NBTTagCompound extends NBTBase
    015{
    016    /**
    017     * The key-value pairs for the tag. Each key is a UTF string, each value is a tag.
    018     */
    019    private Map tagMap = new HashMap();
    020
    021    public NBTTagCompound()
    022    {
    023        super("");
    024    }
    025
    026    public NBTTagCompound(String par1Str)
    027    {
    028        super(par1Str);
    029    }
    030
    031    /**
    032     * Write the actual data contents of the tag, implemented in NBT extension classes
    033     */
    034    void write(DataOutput par1DataOutput) throws IOException
    035    {
    036        Iterator iterator = this.tagMap.values().iterator();
    037
    038        while (iterator.hasNext())
    039        {
    040            NBTBase nbtbase = (NBTBase)iterator.next();
    041            NBTBase.writeNamedTag(nbtbase, par1DataOutput);
    042        }
    043
    044        par1DataOutput.writeByte(0);
    045    }
    046
    047    /**
    048     * Read the actual data contents of the tag, implemented in NBT extension classes
    049     */
    050    void load(DataInput par1DataInput) throws IOException
    051    {
    052        this.tagMap.clear();
    053        NBTBase nbtbase;
    054
    055        while ((nbtbase = NBTBase.readNamedTag(par1DataInput)).getId() != 0)
    056        {
    057            this.tagMap.put(nbtbase.getName(), nbtbase);
    058        }
    059    }
    060
    061    /**
    062     * Returns all the values in the tagMap HashMap.
    063     */
    064    public Collection getTags()
    065    {
    066        return this.tagMap.values();
    067    }
    068
    069    /**
    070     * Gets the type byte for the tag.
    071     */
    072    public byte getId()
    073    {
    074        return (byte)10;
    075    }
    076
    077    /**
    078     * Stores the given tag into the map with the given string key. This is mostly used to store tag lists.
    079     */
    080    public void setTag(String par1Str, NBTBase par2NBTBase)
    081    {
    082        this.tagMap.put(par1Str, par2NBTBase.setName(par1Str));
    083    }
    084
    085    /**
    086     * Stores a new NBTTagByte with the given byte value into the map with the given string key.
    087     */
    088    public void setByte(String par1Str, byte par2)
    089    {
    090        this.tagMap.put(par1Str, new NBTTagByte(par1Str, par2));
    091    }
    092
    093    /**
    094     * Stores a new NBTTagShort with the given short value into the map with the given string key.
    095     */
    096    public void setShort(String par1Str, short par2)
    097    {
    098        this.tagMap.put(par1Str, new NBTTagShort(par1Str, par2));
    099    }
    100
    101    /**
    102     * Stores a new NBTTagInt with the given integer value into the map with the given string key.
    103     */
    104    public void setInteger(String par1Str, int par2)
    105    {
    106        this.tagMap.put(par1Str, new NBTTagInt(par1Str, par2));
    107    }
    108
    109    /**
    110     * Stores a new NBTTagLong with the given long value into the map with the given string key.
    111     */
    112    public void setLong(String par1Str, long par2)
    113    {
    114        this.tagMap.put(par1Str, new NBTTagLong(par1Str, par2));
    115    }
    116
    117    /**
    118     * Stores a new NBTTagFloat with the given float value into the map with the given string key.
    119     */
    120    public void setFloat(String par1Str, float par2)
    121    {
    122        this.tagMap.put(par1Str, new NBTTagFloat(par1Str, par2));
    123    }
    124
    125    /**
    126     * Stores a new NBTTagDouble with the given double value into the map with the given string key.
    127     */
    128    public void setDouble(String par1Str, double par2)
    129    {
    130        this.tagMap.put(par1Str, new NBTTagDouble(par1Str, par2));
    131    }
    132
    133    /**
    134     * Stores a new NBTTagString with the given string value into the map with the given string key.
    135     */
    136    public void setString(String par1Str, String par2Str)
    137    {
    138        this.tagMap.put(par1Str, new NBTTagString(par1Str, par2Str));
    139    }
    140
    141    /**
    142     * Stores a new NBTTagByteArray with the given array as data into the map with the given string key.
    143     */
    144    public void setByteArray(String par1Str, byte[] par2ArrayOfByte)
    145    {
    146        this.tagMap.put(par1Str, new NBTTagByteArray(par1Str, par2ArrayOfByte));
    147    }
    148
    149    /**
    150     * Stores a new NBTTagIntArray with the given array as data into the map with the given string key.
    151     */
    152    public void setIntArray(String par1Str, int[] par2ArrayOfInteger)
    153    {
    154        this.tagMap.put(par1Str, new NBTTagIntArray(par1Str, par2ArrayOfInteger));
    155    }
    156
    157    /**
    158     * Stores the given NBTTagCompound into the map with the given string key.
    159     */
    160    public void setCompoundTag(String par1Str, NBTTagCompound par2NBTTagCompound)
    161    {
    162        this.tagMap.put(par1Str, par2NBTTagCompound.setName(par1Str));
    163    }
    164
    165    /**
    166     * Stores the given boolean value as a NBTTagByte, storing 1 for true and 0 for false, using the given string key.
    167     */
    168    public void setBoolean(String par1Str, boolean par2)
    169    {
    170        this.setByte(par1Str, (byte)(par2 ? 1 : 0));
    171    }
    172
    173    /**
    174     * gets a generic tag with the specified name
    175     */
    176    public NBTBase getTag(String par1Str)
    177    {
    178        return (NBTBase)this.tagMap.get(par1Str);
    179    }
    180
    181    /**
    182     * Returns whether the given string has been previously stored as a key in the map.
    183     */
    184    public boolean hasKey(String par1Str)
    185    {
    186        return this.tagMap.containsKey(par1Str);
    187    }
    188
    189    /**
    190     * Retrieves a byte value using the specified key, or 0 if no such key was stored.
    191     */
    192    public byte getByte(String par1Str)
    193    {
    194        try
    195        {
    196            return !this.tagMap.containsKey(par1Str) ? 0 : ((NBTTagByte)this.tagMap.get(par1Str)).data;
    197        }
    198        catch (ClassCastException classcastexception)
    199        {
    200            throw new ReportedException(this.createCrashReport(par1Str, 1, classcastexception));
    201        }
    202    }
    203
    204    /**
    205     * Retrieves a short value using the specified key, or 0 if no such key was stored.
    206     */
    207    public short getShort(String par1Str)
    208    {
    209        try
    210        {
    211            return !this.tagMap.containsKey(par1Str) ? 0 : ((NBTTagShort)this.tagMap.get(par1Str)).data;
    212        }
    213        catch (ClassCastException classcastexception)
    214        {
    215            throw new ReportedException(this.createCrashReport(par1Str, 2, classcastexception));
    216        }
    217    }
    218
    219    /**
    220     * Retrieves an integer value using the specified key, or 0 if no such key was stored.
    221     */
    222    public int getInteger(String par1Str)
    223    {
    224        try
    225        {
    226            return !this.tagMap.containsKey(par1Str) ? 0 : ((NBTTagInt)this.tagMap.get(par1Str)).data;
    227        }
    228        catch (ClassCastException classcastexception)
    229        {
    230            throw new ReportedException(this.createCrashReport(par1Str, 3, classcastexception));
    231        }
    232    }
    233
    234    /**
    235     * Retrieves a long value using the specified key, or 0 if no such key was stored.
    236     */
    237    public long getLong(String par1Str)
    238    {
    239        try
    240        {
    241            return !this.tagMap.containsKey(par1Str) ? 0L : ((NBTTagLong)this.tagMap.get(par1Str)).data;
    242        }
    243        catch (ClassCastException classcastexception)
    244        {
    245            throw new ReportedException(this.createCrashReport(par1Str, 4, classcastexception));
    246        }
    247    }
    248
    249    /**
    250     * Retrieves a float value using the specified key, or 0 if no such key was stored.
    251     */
    252    public float getFloat(String par1Str)
    253    {
    254        try
    255        {
    256            return !this.tagMap.containsKey(par1Str) ? 0.0F : ((NBTTagFloat)this.tagMap.get(par1Str)).data;
    257        }
    258        catch (ClassCastException classcastexception)
    259        {
    260            throw new ReportedException(this.createCrashReport(par1Str, 5, classcastexception));
    261        }
    262    }
    263
    264    /**
    265     * Retrieves a double value using the specified key, or 0 if no such key was stored.
    266     */
    267    public double getDouble(String par1Str)
    268    {
    269        try
    270        {
    271            return !this.tagMap.containsKey(par1Str) ? 0.0D : ((NBTTagDouble)this.tagMap.get(par1Str)).data;
    272        }
    273        catch (ClassCastException classcastexception)
    274        {
    275            throw new ReportedException(this.createCrashReport(par1Str, 6, classcastexception));
    276        }
    277    }
    278
    279    /**
    280     * Retrieves a string value using the specified key, or an empty string if no such key was stored.
    281     */
    282    public String getString(String par1Str)
    283    {
    284        try
    285        {
    286            return !this.tagMap.containsKey(par1Str) ? "" : ((NBTTagString)this.tagMap.get(par1Str)).data;
    287        }
    288        catch (ClassCastException classcastexception)
    289        {
    290            throw new ReportedException(this.createCrashReport(par1Str, 8, classcastexception));
    291        }
    292    }
    293
    294    /**
    295     * Retrieves a byte array using the specified key, or a zero-length array if no such key was stored.
    296     */
    297    public byte[] getByteArray(String par1Str)
    298    {
    299        try
    300        {
    301            return !this.tagMap.containsKey(par1Str) ? new byte[0] : ((NBTTagByteArray)this.tagMap.get(par1Str)).byteArray;
    302        }
    303        catch (ClassCastException classcastexception)
    304        {
    305            throw new ReportedException(this.createCrashReport(par1Str, 7, classcastexception));
    306        }
    307    }
    308
    309    /**
    310     * Retrieves an int array using the specified key, or a zero-length array if no such key was stored.
    311     */
    312    public int[] getIntArray(String par1Str)
    313    {
    314        try
    315        {
    316            return !this.tagMap.containsKey(par1Str) ? new int[0] : ((NBTTagIntArray)this.tagMap.get(par1Str)).intArray;
    317        }
    318        catch (ClassCastException classcastexception)
    319        {
    320            throw new ReportedException(this.createCrashReport(par1Str, 11, classcastexception));
    321        }
    322    }
    323
    324    /**
    325     * Retrieves a NBTTagCompound subtag matching the specified key, or a new empty NBTTagCompound if no such key was
    326     * stored.
    327     */
    328    public NBTTagCompound getCompoundTag(String par1Str)
    329    {
    330        try
    331        {
    332            return !this.tagMap.containsKey(par1Str) ? new NBTTagCompound(par1Str) : (NBTTagCompound)this.tagMap.get(par1Str);
    333        }
    334        catch (ClassCastException classcastexception)
    335        {
    336            throw new ReportedException(this.createCrashReport(par1Str, 10, classcastexception));
    337        }
    338    }
    339
    340    /**
    341     * Retrieves a NBTTagList subtag matching the specified key, or a new empty NBTTagList if no such key was stored.
    342     */
    343    public NBTTagList getTagList(String par1Str)
    344    {
    345        try
    346        {
    347            return !this.tagMap.containsKey(par1Str) ? new NBTTagList(par1Str) : (NBTTagList)this.tagMap.get(par1Str);
    348        }
    349        catch (ClassCastException classcastexception)
    350        {
    351            throw new ReportedException(this.createCrashReport(par1Str, 9, classcastexception));
    352        }
    353    }
    354
    355    /**
    356     * Retrieves a boolean value using the specified key, or false if no such key was stored. This uses the getByte
    357     * method.
    358     */
    359    public boolean getBoolean(String par1Str)
    360    {
    361        return this.getByte(par1Str) != 0;
    362    }
    363
    364    /**
    365     * Remove the specified tag.
    366     */
    367    public void removeTag(String par1Str)
    368    {
    369        this.tagMap.remove(par1Str);
    370    }
    371
    372    public String toString()
    373    {
    374        String s = this.getName() + ":[";
    375        String s1;
    376
    377        for (Iterator iterator = this.tagMap.keySet().iterator(); iterator.hasNext(); s = s + s1 + ":" + this.tagMap.get(s1) + ",")
    378        {
    379            s1 = (String)iterator.next();
    380        }
    381
    382        return s + "]";
    383    }
    384
    385    /**
    386     * Return whether this compound has no tags.
    387     */
    388    public boolean hasNoTags()
    389    {
    390        return this.tagMap.isEmpty();
    391    }
    392
    393    /**
    394     * Create a crash report which indicates a NBT read error.
    395     */
    396    private CrashReport createCrashReport(String par1Str, int par2, ClassCastException par3ClassCastException)
    397    {
    398        CrashReport crashreport = CrashReport.makeCrashReport(par3ClassCastException, "Reading NBT data");
    399        CrashReportCategory crashreportcategory = crashreport.makeCategoryDepth("Corrupt NBT tag", 1);
    400        crashreportcategory.addCrashSectionCallable("Tag type found", new CallableTagCompound1(this, par1Str));
    401        crashreportcategory.addCrashSectionCallable("Tag type expected", new CallableTagCompound2(this, par2));
    402        crashreportcategory.addCrashSection("Tag name", par1Str);
    403
    404        if (this.getName() != null && this.getName().length() > 0)
    405        {
    406            crashreportcategory.addCrashSection("Tag parent", this.getName());
    407        }
    408
    409        return crashreport;
    410    }
    411
    412    /**
    413     * Creates a clone of the tag.
    414     */
    415    public NBTBase copy()
    416    {
    417        NBTTagCompound nbttagcompound = new NBTTagCompound(this.getName());
    418        Iterator iterator = this.tagMap.keySet().iterator();
    419
    420        while (iterator.hasNext())
    421        {
    422            String s = (String)iterator.next();
    423            nbttagcompound.setTag(s, ((NBTBase)this.tagMap.get(s)).copy());
    424        }
    425
    426        return nbttagcompound;
    427    }
    428
    429    public boolean equals(Object par1Obj)
    430    {
    431        if (super.equals(par1Obj))
    432        {
    433            NBTTagCompound nbttagcompound = (NBTTagCompound)par1Obj;
    434            return this.tagMap.entrySet().equals(nbttagcompound.tagMap.entrySet());
    435        }
    436        else
    437        {
    438            return false;
    439        }
    440    }
    441
    442    public int hashCode()
    443    {
    444        return super.hashCode() ^ this.tagMap.hashCode();
    445    }
    446
    447    /**
    448     * Return the tag map for this compound.
    449     */
    450    static Map getTagMap(NBTTagCompound par0NBTTagCompound)
    451    {
    452        return par0NBTTagCompound.tagMap;
    453    }
    454}