void ReadTagHeader(bool readName) { // Setting state to error in case reader throws NbtParseState oldState = state; state = NbtParseState.Error; TagsRead++; TagName = (readName ? reader.ReadString() : null); valueCache = null; TagLength = 0; atValue = false; ListType = NbtTagType.Unknown; switch (TagType) { case NbtTagType.Byte: case NbtTagType.Short: case NbtTagType.Int: case NbtTagType.Long: case NbtTagType.Float: case NbtTagType.Double: case NbtTagType.String: atValue = true; state = oldState; break; case NbtTagType.IntArray: case NbtTagType.ByteArray: case NbtTagType.LongArray: TagLength = reader.ReadInt32(); if (TagLength < 0) { throw new NbtFormatException("Negative array length given: " + TagLength); } atValue = true; state = oldState; break; case NbtTagType.List: ListType = reader.ReadTagType(); TagLength = reader.ReadInt32(); if (TagLength < 0) { throw new NbtFormatException("Negative tag length given: " + TagLength); } state = NbtParseState.AtListBeginning; break; case NbtTagType.Compound: state = NbtParseState.AtCompoundBeginning; break; default: // This should not happen unless NbtBinaryReader is bugged throw new NbtFormatException("Trying to read tag of unknown type."); } }
void ReadTagHeader(bool readName) { TagsRead++; TagName = (readName ? reader.ReadString() : null); valueCache = null; TagLength = 0; atValue = false; ListType = NbtTagType.Unknown; switch (TagType) { case NbtTagType.Byte: case NbtTagType.Short: case NbtTagType.Int: case NbtTagType.Long: case NbtTagType.Float: case NbtTagType.Double: case NbtTagType.String: atValue = true; break; case NbtTagType.IntArray: case NbtTagType.ByteArray: TagLength = reader.ReadInt32(); atValue = true; break; case NbtTagType.List: ListType = reader.ReadTagType(); TagLength = reader.ReadInt32(); state = NbtParseState.AtListBeginning; break; case NbtTagType.Compound: state = NbtParseState.AtCompoundBeginning; break; default: throw new NbtFormatException("Trying to read tag of unknown type."); } }
public T[] ReadListAsArray <T>() { switch (state) { case NbtParseState.AtStreamEnd: throw new EndOfStreamException(); case NbtParseState.Error: throw new InvalidReaderStateException(ErroneousStateError); case NbtParseState.AtListBeginning: GoDown(); ListIndex = 0; TagType = ListType; state = NbtParseState.InList; break; case NbtParseState.InList: break; default: throw new InvalidOperationException("ReadListAsArray may only be used on List tags."); } int elementsToRead = ParentTagLength - ListIndex; // special handling for reading byte arrays (as byte arrays) if (ListType == NbtTagType.Byte && typeof(T) == typeof(byte)) { TagsRead += elementsToRead; ListIndex = ParentTagLength - 1; T[] val = (T[])(object)reader.ReadBytes(elementsToRead); if (val.Length < elementsToRead) { throw new EndOfStreamException(); } return(val); } // for everything else, gotta read elements one-by-one var result = new T[elementsToRead]; switch (ListType) { case NbtTagType.Byte: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadByte(), typeof(T)); } break; case NbtTagType.Short: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadInt16(), typeof(T)); } break; case NbtTagType.Int: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadInt32(), typeof(T)); } break; case NbtTagType.Long: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadInt64(), typeof(T)); } break; case NbtTagType.Float: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadSingle(), typeof(T)); } break; case NbtTagType.Double: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadDouble(), typeof(T)); } break; case NbtTagType.String: for (int i = 0; i < elementsToRead; i++) { result[i] = (T)Convert.ChangeType(reader.ReadString(), typeof(T)); } break; default: throw new InvalidOperationException("ReadListAsArray may only be used on lists of value types."); } TagsRead += elementsToRead; ListIndex = ParentTagLength - 1; return(result); }
/// <summary> Reads the next tag from the stream. </summary> /// <returns> true if the next tag was read successfully; false if there are no more tags to read. </returns> /// <exception cref="NbtFormatException"> If an error occurred while parsing data in NBT format. </exception> /// <exception cref="InvalidReaderStateException"> If NbtReader cannot recover from a previous parsing error. </exception> public bool ReadToFollowing() { switch (state) { case NbtParseState.AtStreamBeginning: // set state to error in case reader.ReadTagType throws. state = NbtParseState.Error; // read first tag, make sure it's a compound if (reader.ReadTagType() != NbtTagType.Compound) { throw new NbtFormatException("Given NBT stream does not start with a TAG_Compound"); } Depth = 1; TagType = NbtTagType.Compound; // Read root name. Advance to the first inside tag. ReadTagHeader(true); RootName = TagName; return(true); case NbtParseState.AtCompoundBeginning: GoDown(); state = NbtParseState.InCompound; goto case NbtParseState.InCompound; case NbtParseState.InCompound: state = NbtParseState.Error; if (atValue) { SkipValue(); } // Read next tag, check if we've hit the end if (canSeekStream) { TagStartOffset = (int)(reader.BaseStream.Position - streamStartOffset); } // set state to error in case reader.ReadTagType throws. TagType = reader.ReadTagType(); state = NbtParseState.InCompound; if (TagType == NbtTagType.End) { TagName = null; TagsRead++; state = NbtParseState.AtCompoundEnd; if (SkipEndTags) { TagsRead--; goto case NbtParseState.AtCompoundEnd; } else { return(true); } } else { ReadTagHeader(true); return(true); } case NbtParseState.AtListBeginning: GoDown(); ListIndex = -1; TagType = ListType; state = NbtParseState.InList; goto case NbtParseState.InList; case NbtParseState.InList: state = NbtParseState.Error; if (atValue) { SkipValue(); } ListIndex++; if (ListIndex >= ParentTagLength) { GoUp(); if (ParentTagType == NbtTagType.List) { state = NbtParseState.InList; TagType = NbtTagType.List; goto case NbtParseState.InList; } else if (ParentTagType == NbtTagType.Compound) { state = NbtParseState.InCompound; goto case NbtParseState.InCompound; } else { // This should not happen unless NbtReader is bugged throw new NbtFormatException(InvalidParentTagError); } } else { if (canSeekStream) { TagStartOffset = (int)(reader.BaseStream.Position - streamStartOffset); } state = NbtParseState.InList; ReadTagHeader(false); } return(true); case NbtParseState.AtCompoundEnd: GoUp(); if (ParentTagType == NbtTagType.List) { state = NbtParseState.InList; TagType = NbtTagType.Compound; goto case NbtParseState.InList; } else if (ParentTagType == NbtTagType.Compound) { state = NbtParseState.InCompound; goto case NbtParseState.InCompound; } else if (ParentTagType == NbtTagType.Unknown) { state = NbtParseState.AtStreamEnd; return(false); } else { // This should not happen unless NbtReader is bugged state = NbtParseState.Error; throw new NbtFormatException(InvalidParentTagError); } case NbtParseState.AtStreamEnd: // nothing left to read! return(false); default: // Parsing error, or unexpected state. throw new InvalidReaderStateException(ErroneousStateError); } }