예제 #1
0
        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);
        }
예제 #2
0
        private int PushChunkRead(bool firstChunk)
        {
            Chunk chunk;
            int   err;

            byte[] buffer;

            var top = GetCurrentContext();

            if (top == null && !firstChunk)
            {
                return((int)ParserStatus.EndOfFile);
            }
            var type = top != null ? top.Type : 0;

            if (firstChunk)
            {
                buffer = new byte[Marshal.SizeOf <SmallChunk>()];
                err    = _streamOperations.Read(_ioContext, buffer, 0, buffer.Length);
                if (err != Marshal.SizeOf <SmallChunk>())
                {
                    if (err >= 0)
                    {
                        err = (int)ParserStatus.NotIFF;
                    }
                    return(err);
                }
                var smallChunk = Marshal.BytesToStruct <SmallChunk>(buffer);
                chunk.Id   = smallChunk.Id;
                chunk.Size = smallChunk.Size;

                if (chunk.Size == (ulong)ChunkSize.Known64Bit)
                {
                    buffer = new byte[chunk.Size];
                    err    = _streamOperations.Read(_ioContext, buffer, 0, buffer.Length);
                    if ((ulong)err != chunk.Size)
                    {
                        if (err >= 0)
                        {
                            err = (int)ParserStatus.NotIFF;
                        }
                        return(err);
                    }
                    chunk.Size = BitConverter.ToUInt32(buffer, 0);
                }
                else if (chunk.Size >= (ulong)ChunkSize.Reserved)
                {
                    return((int)ParserStatus.Mangled);
                }
            }
            else
            {
                /* Using ReadChunk() causes these bytes to go into the
                 * parent's scan count
                 */
                buffer = new byte[Marshal.SizeOf <SmallChunk>()];
                err    = ReadChunk(buffer, 0, buffer.Length);
                if (err != Marshal.SizeOf <SmallChunk>())
                {
                    if (err >= 0)
                    {
                        err = (int)ParserStatus.PrematureEndOfFile;
                    }
                    return(err);
                }

                var smallChunk = Marshal.BytesToStruct <SmallChunk>(buffer);
                chunk.Id   = smallChunk.Id;
                chunk.Size = smallChunk.Size;

                if (chunk.Size == (ulong)ChunkSize.Known64Bit)
                {
                    buffer = new byte[chunk.Size];
                    err    = _streamOperations.Read(_ioContext, buffer, 0, buffer.Length);
                    if ((ulong)err != chunk.Size)
                    {
                        if (err >= 0)
                        {
                            err = (int)ParserStatus.NotIFF;
                        }
                        return(err);
                    }
                    chunk.Size = BitConverter.ToUInt32(buffer, 0);
                }
                else if (chunk.Size >= (ulong)ChunkSize.Reserved)
                {
                    return((int)ParserStatus.Mangled);
                }
                if (chunk.Size > (top.Size - top.Offset))
                {
                    return((int)ParserStatus.Mangled);
                }
            }
            if (IdUtility.IsGoodId(chunk.Id))
            {
                try {
                    var contextNode = new ContextNode(chunk.Id, type);
                    contextNode.Size        = chunk.Size;
                    contextNode.Offset      = 0;
                    contextNode.CurrentSize = chunk.Size;

                    _stack.AddHead(contextNode);
                    return(0);
                } catch (OutOfMemoryException) {
                    return((int)ParserStatus.OutOfMemory);
                }
            }
            if (this._newIO)
            {
                return((int)ParserStatus.NotIFF);
            }
            return((int)ParserStatus.SyntaxError);
        }