/// <summary> /// Writes the chunk. /// </summary> /// <returns>The chunk.</returns> /// <param name="buffer">Buffer.</param> /// <param name="offset">Offset.</param> /// <param name="count">Count.</param> public int WriteChunk(byte[] buffer, int offset, int count) { var top = GetCurrentContext(); if (top == null) { return((int)ParserStatus.EndOfFile); } if (IdUtility.IsGenericId(top.Id)) { return((int)ParserStatus.NotIFF); } return(WriteChunkInternal(top, buffer, offset, count)); }
/// <summary> ///Test current state and advance to the next state. State is one of: /// - Start of file if iff_NewIO is TRUE. /// Push initial chunk, get its info and return. /// /// - Poised at end of chunk if iff_Paused is TRUE. /// PopChunk() the current context. The top context will then be a generic /// or end of file. Return EOF if the latter. If this chunk is exhausted, /// pause again and return, otherwise push new chunk and return. /// /// - Inside a generic chunk. /// Push a new context and return. /// /// - Inside a non-generic chunk. /// Pause and return. /// </summary> /// <returns>The state.</returns> private int NextState() { ContextNode top; int err; uint topId; /* deal with the case of the first chunk */ if (_newIO) { err = PushChunkRead(true); _newIO = false; _paused = false; if (err < 0) { return(err); } top = GetCurrentContext(); if ((top.Id != GenericChunkIds.ID_FORM) && (top.Id != GenericChunkIds.ID_CAT) && (top.Id != GenericChunkIds.ID_LIST) && (!IsContainerId(top.Id))) { return((int)ParserStatus.NotIFF); } if ((top.Size & 1) == 1) { /* containers must inherently be word-aligned */ return((int)ParserStatus.Mangled); } return(ReadGenericType()); } /* In the PAUSE state, do the deferred PopChunk() */ if (_paused) { err = PopChunk(); if (err < 0) { return(err); } _paused = false; } /* If no top context node then the file is exhausted. */ if ((top = GetCurrentContext()) == null) { return((int)ParserStatus.EndOfFile); } topId = top.Id; if (IdUtility.IsGenericId(topId) || IsContainerId(topId)) { /* If inside a generic chunk, and not exhausted, push a subchunk. */ if (top.Offset < top.Size) { err = PushChunkRead(false); if (err < 0) { return(err); } top = GetCurrentContext(); /* If non-generic, we're done, but if the containing chunk is not * FORM or PROP, it's an IFF syntax error. */ if (!IdUtility.IsGenericId(top.Id)) { if ((topId != GenericChunkIds.ID_FORM) && (topId != GenericChunkIds.ID_PROP) && (!IsContainerId(topId))) { return((int)ParserStatus.SyntaxError); } return(0); } /* If this new chunk is generic, and is a PROP, test to see if it's * in the right place -- containing chunk should be a LIST. */ if ((top.Id == GenericChunkIds.ID_PROP) && (topId != GenericChunkIds.ID_LIST)) { return((int)ParserStatus.SyntaxError); } /* since it's an ok generic, get its type and return */ return(ReadGenericType()); } else if (top.Offset != top.Size) { /* If not exhaused, this is a junky IFF file */ return((int)ParserStatus.Mangled); } } /* If the generic is exhausted, or this is a non-generic chunk, * enter the pause state and return flag. */ _paused = true; return((int)ParserStatus.EndOfContext); }
private int PushChunkWrite(uint type, uint id, uint size) { ContextNode cn; int err; uint parentType; Chunk chunk; SmallChunk smallChunk; bool firstChunk; byte[] buffer; if ((cn = GetCurrentContext()) != null) { parentType = cn.Type; firstChunk = false; } else if (_newIO) { parentType = 0; firstChunk = true; _newIO = false; /* first chunk must be FORM, CAT, or LIST */ if ((id != GenericChunkIds.ID_FORM) && (id != GenericChunkIds.ID_CAT) && (id != GenericChunkIds.ID_LIST)) { return((int)ParserStatus.NotIFF); } } else { return((int)ParserStatus.EndOfFile); } if (!IdUtility.IsGoodId(id)) { return((int)ParserStatus.SyntaxError); } if (IdUtility.IsGenericId(id)) { if (id == GenericChunkIds.ID_PROP) { /* the containing context for PROP must be a LIST */ if (cn.Id != GenericChunkIds.ID_LIST) { return((int)ParserStatus.SyntaxError); } } /* Generic ID. Check the validity of its subtype. */ if (!IdUtility.IsGoodType(type)) { return((int)ParserStatus.NotIFF); } } else { /* Non-generic ID. Containing context must be PROP or FORM or container */ if ((cn.Id != GenericChunkIds.ID_FORM) && (cn.Id != GenericChunkIds.ID_PROP) && (!IsContainerId(cn.Id))) { return((int)ParserStatus.SyntaxError); } } /* Write the chunk header: ID and size (if IFF_SIZE_UNKNOWN, it will * be patched later by PopChunkW()). */ if ((size >= (uint)ChunkSize.Reserved) && (size != (uint)ChunkSize.Unknown32Bit)) { chunk.Id = id; chunk.Filler = (uint)ChunkSize.Known64Bit; chunk.Size = size; buffer = Marshal.StructToBytes(chunk); if (firstChunk) { err = _streamOperations.Write(_ioContext, buffer, 0, buffer.Length); } else { /* Update parent's count of bytes written. */ err = WriteChunkInternal(cn, buffer, 0, buffer.Length); } } else { smallChunk.Id = id; smallChunk.Size = size; buffer = Marshal.StructToBytes(smallChunk); if (firstChunk) { err = _streamOperations.Write(_ioContext, buffer, 0, buffer.Length); } else { /* Update parent's count of bytes written. */ err = WriteChunkInternal(cn, buffer, 0, buffer.Length); } } if (err < 0) { return(err); } /* Allocate and fill in a ContextNode for the new chunk */ cn = new ContextNode(id, 0); cn.Size = size; cn.Offset = 0; cn.CurrentSize = 0; _stack.AddHead(cn); /* For generic chunks, write the type out now that * the chunk context node is initialized. */ if (IdUtility.IsGenericId(id) || IsContainerId(id)) { if (IdUtility.IsGenericId(id)) { var bigEndianType = type; Swap(ref bigEndianType); buffer = BitConverter.GetBytes(bigEndianType); err = WriteChunkInternal(cn, buffer, 0, buffer.Length); cn.Type = type; } else { cn.Type = 0; } } else { cn.Type = parentType; } return(err); }