Example #1
0
        ///////////////////////////////////////////////////////////////////////////////////////////////

        #region IExecute Members
        public override ReturnCode Execute(
            Interpreter interpreter,
            IClientData clientData,
            ArgumentList arguments,
            ref Result result
            )
        {
            ReturnCode code = ReturnCode.Ok;

            if (interpreter != null)
            {
                if (arguments != null)
                {
                    if (arguments.Count >= 3)
                    {
                        OptionDictionary options = new OptionDictionary(
                            new IOption[] {
                            new Option(null, OptionFlags.MustHaveIntegerValue, Index.Invalid, Index.Invalid, "-size", null),
                            new Option(null, OptionFlags.MustHaveValue | OptionFlags.Unsupported, Index.Invalid, Index.Invalid, "-command", null),
                            new Option(typeof(EventFlags), OptionFlags.MustHaveEnumValue, Index.Invalid, Index.Invalid, "-eventflags",
                                       new Variant(interpreter.EngineEventFlags)),
                            new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null)
                        });

                        int argumentIndex = Index.Invalid;

                        if (arguments.Count > 3)
                        {
                            code = interpreter.GetOptions(options, arguments, 0, 3, Index.Invalid, true, ref argumentIndex, ref result);
                        }
                        else
                        {
                            code = ReturnCode.Ok;
                        }

                        if (code == ReturnCode.Ok)
                        {
                            if (argumentIndex == Index.Invalid)
                            {
                                Variant value = null;
                                int     size  = _Size.Invalid;

                                if (options.IsPresent("-size", ref value))
                                {
                                    size = (int)value.Value;

                                    //
                                    // NOTE: All negative values become "invalid",
                                    //       which means "read until end-of-file".
                                    //
                                    if (size < 0)
                                    {
                                        size = _Size.Invalid;
                                    }
                                }

#if MONO_BUILD
#pragma warning disable 219
#endif
                                string command = null; // NOTE: Flagged by the Mono C# compiler.
#if MONO_BUILD
#pragma warning restore 219
#endif

                                if (options.IsPresent("-command", ref value))
                                {
                                    command = value.ToString(); /* NOT YET IMPLEMENTED */
                                }
                                EventFlags eventFlags = interpreter.EngineEventFlags;

                                if (options.IsPresent("-eventflags", ref value))
                                {
                                    eventFlags = (EventFlags)value.Value;
                                }

                                string  inputChannelId = arguments[1];
                                Channel inputChannel   = interpreter.GetChannel(inputChannelId, ref result);

                                if (inputChannel != null)
                                {
                                    if (inputChannel.CanRead)
                                    {
                                        Encoding inputEncoding = null;

                                        if (interpreter.GetChannelEncoding(inputChannel, ref inputEncoding) == ReturnCode.Ok)
                                        {
                                            string  outputChannelId = arguments[2];
                                            Channel outputChannel   = interpreter.GetChannel(outputChannelId, ref result);

                                            if (outputChannel != null)
                                            {
                                                if (outputChannel.CanWrite)
                                                {
                                                    Encoding outputEncoding = null;

                                                    if (interpreter.GetChannelEncoding(outputChannel, ref outputEncoding) == ReturnCode.Ok)
                                                    {
                                                        try
                                                        {
                                                            BinaryWriter binaryWriter = null; /* NOTE: Output channel. */
                                                            int          outputBytes  = 0;

                                                            //
                                                            // NOTE: Reset the end-of-file indicator here because we may
                                                            //       need to use it to terminate the loop.
                                                            //
                                                            inputChannel.HitEndOfStream = false;

                                                            do
                                                            {
                                                                if (inputChannel.CanSeek && inputChannel.EndOfStream)
                                                                {
                                                                    break;
                                                                }
                                                                else if (inputChannel.HitEndOfStream)
                                                                {
                                                                    break;
                                                                }

                                                                ByteList inputBuffer = null;

                                                                int readSize = size;

                                                                if ((readSize != _Size.Invalid) && (readSize > MaximumReadSize))
                                                                {
                                                                    readSize = MaximumReadSize;
                                                                }

                                                                if (readSize == _Size.Invalid)
                                                                {
                                                                    code = inputChannel.Read(null, false, ref inputBuffer, ref result);
                                                                }
                                                                else
                                                                {
                                                                    code = inputChannel.Read(readSize, null, false, ref inputBuffer, ref result);
                                                                }

                                                                if (code == ReturnCode.Ok)
                                                                {
                                                                    //
                                                                    // NOTE: Grab the input byte array from the input
                                                                    //       buffer byte list.
                                                                    //
                                                                    byte[] inputArray = inputBuffer.ToArray();

                                                                    //
                                                                    // NOTE: Update the total input byte count with the
                                                                    //       number of bytes we just read.
                                                                    //
                                                                    if (size != _Size.Invalid)
                                                                    {
                                                                        size -= inputArray.Length;
                                                                    }

                                                                    if (outputChannel.IsVirtualOutput)
                                                                    {
                                                                        //
                                                                        // NOTE: Virtual output means that we must get
                                                                        //       the text for the input bytes.
                                                                        //
                                                                        string stringValue = null;

                                                                        code = StringOps.GetString(
                                                                            inputEncoding, inputArray, EncodingType.Binary,
                                                                            ref stringValue, ref result);

                                                                        if (code == ReturnCode.Ok)
                                                                        {
                                                                            //
                                                                            // NOTE: The encoding is ignored, because this is
                                                                            //       directly from the input string, which is
                                                                            //       already Unicode.
                                                                            //
                                                                            outputChannel.AppendVirtualOutput(stringValue);

                                                                            //
                                                                            // NOTE: Update the total output byte count with
                                                                            //       the number of bytes we just wrote.
                                                                            //
                                                                            code = StringOps.GetByteCount(
                                                                                inputEncoding, stringValue, EncodingType.Binary,
                                                                                ref outputBytes, ref result);
                                                                        }
                                                                    }
                                                                    else
                                                                    {
                                                                        if (binaryWriter == null)
                                                                        {
                                                                            binaryWriter = interpreter.GetChannelBinaryWriter(
                                                                                outputChannel);
                                                                        }

                                                                        if (binaryWriter != null)
                                                                        {
                                                                            //
                                                                            // NOTE: Convert the input bytes into output
                                                                            //       bytes based on both the input and
                                                                            //       output encodings, if any.  If both
                                                                            //       encodings are null, the input bytes
                                                                            //       are used verbatim.
                                                                            //
                                                                            byte[] outputArray = null;

                                                                            code = StringOps.ConvertBytes(
                                                                                inputEncoding, outputEncoding, EncodingType.Binary,
                                                                                EncodingType.Binary, inputArray, ref outputArray,
                                                                                ref result);

                                                                            if (code == ReturnCode.Ok)
                                                                            {
                                                                                //
                                                                                // NOTE: Ready the output channel for "append"
                                                                                //       mode, if necessary.
                                                                                //
                                                                                outputChannel.CheckAppend(); /* throw */

                                                                                //
                                                                                // NOTE: Attempt to write the output bytes to
                                                                                //       the output channel.
                                                                                //
                                                                                binaryWriter.Write(outputArray); /* throw */

#if MONO || MONO_HACKS
                                                                                //
                                                                                // HACK: *MONO* As of Mono 2.8.0, it seems that
                                                                                //       Mono "loses" output unless a flush is
                                                                                //       performed right after a write.  So far,
                                                                                //       this has only been observed for the
                                                                                //       console channels; however, always using
                                                                                //       flush here on Mono shouldn't cause too
                                                                                //       many problems, except a slight loss in
                                                                                //       performance.
                                                                                //       https://bugzilla.novell.com/show_bug.cgi?id=645193
                                                                                //
                                                                                if (CommonOps.Runtime.IsMono())
                                                                                {
                                                                                    binaryWriter.Flush(); /* throw */
                                                                                }
                                                                                else
#endif
                                                                                {
                                                                                    //
                                                                                    // NOTE: Check if we should automatically
                                                                                    //       flush the channel after each write
                                                                                    //       done by this command.
                                                                                    //
                                                                                    /* IGNORED */
                                                                                    outputChannel.CheckAutoFlush();
                                                                                }

                                                                                //
                                                                                // NOTE: Update the total output byte count with
                                                                                //       the number of bytes we just wrote.
                                                                                //
                                                                                outputBytes += outputArray.Length;
                                                                            }
                                                                        }
                                                                        else
                                                                        {
                                                                            result = String.Format(
                                                                                "failed to get binary writer for channel \"{0}\"",
                                                                                outputChannelId);

                                                                            code = ReturnCode.Error;
                                                                        }
                                                                    }
                                                                }

                                                                //
                                                                // NOTE: If any of the above actions failed, bail out of the
                                                                //       copy loop now.
                                                                //
                                                                if (code != ReturnCode.Ok)
                                                                {
                                                                    break;
                                                                }

                                                                //
                                                                // NOTE: Are we done reading input bytes?  If this value is
                                                                //       less than zero, it means we read until end-of-file.
                                                                //       If we have read the specified number of bytes, bail
                                                                //       out.
                                                                //
                                                                if (size == 0)
                                                                {
                                                                    break;
                                                                }

                                                                //
                                                                // NOTE: Check for any pending events in the interpreter and
                                                                //       service them now.
                                                                //
                                                                code = Engine.CheckEvents(interpreter, eventFlags, ref result);

                                                                if (code != ReturnCode.Ok)
                                                                {
                                                                    break;
                                                                }
                                                            }while (true);

                                                            //
                                                            // NOTE: Return the number of bytes written to the output
                                                            //       channel.
                                                            //
                                                            if (code == ReturnCode.Ok)
                                                            {
                                                                result = outputBytes;
                                                            }
                                                        }
                                                        catch (Exception e)
                                                        {
                                                            Engine.SetExceptionErrorCode(interpreter, e);

                                                            result = e;
                                                            code   = ReturnCode.Error;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        result = String.Format(
                                                            "failed to get encoding for output channel \"{0}\"",
                                                            outputChannelId);

                                                        code = ReturnCode.Error;
                                                    }
                                                }
                                                else
                                                {
                                                    result = String.Format(
                                                        "channel \"{0}\" wasn't opened for writing",
                                                        outputChannelId);

                                                    code = ReturnCode.Error;
                                                }
                                            }
                                            else
                                            {
                                                code = ReturnCode.Error;
                                            }
                                        }
                                        else
                                        {
                                            result = String.Format(
                                                "failed to get encoding for input channel \"{0}\"",
                                                inputChannelId);

                                            code = ReturnCode.Error;
                                        }
                                    }
                                    else
                                    {
                                        result = String.Format(
                                            "channel \"{0}\" wasn't opened for reading",
                                            inputChannelId);

                                        code = ReturnCode.Error;
                                    }
                                }
                                else
                                {
                                    code = ReturnCode.Error;
                                }
                            }
                            else
                            {
                                result = "wrong # args: should be \"fcopy input output ?-size size? ?-command callback?\"";
                                code   = ReturnCode.Error;
                            }
                        }
                    }
                    else
                    {
                        result = "wrong # args: should be \"fcopy input output ?-size size? ?-command callback?\"";
                        code   = ReturnCode.Error;
                    }
                }
                else
                {
                    result = "invalid argument list";
                    code   = ReturnCode.Error;
                }
            }
            else
            {
                result = "invalid interpreter";
                code   = ReturnCode.Error;
            }

            return(code);
        }