Beispiel #1
0
        private static string chunksToString(List <chunk> chunks)
        {
            var result     = new StringBuilder();
            int lineLength = 0;

            foreach (var chunk in chunks)
            {
                // RFC 2047: An 'encoded-word' may not be more than 75 characters long. Each line of a header field that contains one or more 'encoded-word's is limited to 76 characters.
                if (chunk.Text != null)
                {
                    result.Append(chunk.Text);
                    lineLength += chunk.Text.Length;
                    while (lineLength > 76)
                    {
                        wrap(result, ref lineLength, 76);
                    }
                }
                else // chunk.Base64 != null
                {
                    // base-64 chunks must be surrounded by "=?utf-8?B?" and followed by "?=". It can be split anywhere except across a UTF-8 sequence.
                    // The minimum space occupied by an encoded-word is 16 characters (because the base64 has to be padded, so min. 4 chars)
                    // This min. length (16 chars) is also guaranteed to be achievable because even the longest unicode sequences can be encoded in four base64 characters.
                    int pos = 0;
                    while (pos < chunk.Base64.Length)
                    {
                        // The first time round is special, because it's the only time when we might wrap _before_ adding a chunk
                        if (pos == 0 && lineLength > 76 - 16)
                        {
                            wrap(result, ref lineLength, 76);
                        }
                        // Figure out how many bytes we can add. Every 3 bytes take 4 characters.
                        int bytes = Math.Min(chunk.Base64.Length - pos, (76 - lineLength - 12) / 4 * 3);
                        Ut.Assert(bytes > 0);
                        // Now move backwards until we hit a utf8 boundary
                        while (pos + bytes < chunk.Base64.Length && chunk.Base64[pos + bytes] >= 0x80 && chunk.Base64[pos + bytes] < 0xC0)
                        {
                            bytes--;
                        }
                        Ut.Assert(bytes > 0);
                        // Add them!
                        lineLength -= result.Length; // coupled with the next change, this increments lineLength by how many chars we're about to append.
                        result.Append("=?UTF-8?B?");
                        result.Append(Convert.ToBase64String(chunk.Base64, pos, bytes));
                        result.Append("?=");
                        lineLength += result.Length;
                        pos        += bytes;
                        // If we have any bytes left, we must wrap, because that's the only reason we would ever not append everything
                        if (pos < chunk.Base64.Length)
                        {
                            result.Append("\r\n ");
                            lineLength = 1;
                        }
                    }
                }
            }

            return(result.ToString());
        }
Beispiel #2
0
            public byte[] GetEntireOutput()
            {
                Ut.Assert(_captureEntire);
                var result = new byte[_chunks.Sum(ch => ch.Length)];
                int offset = 0;

                foreach (var chunk in _chunks)
                {
                    Buffer.BlockCopy(chunk.Data, 0, result, offset, chunk.Length);
                    offset += chunk.Length;
                }
                return(result);
            }
Beispiel #3
0
            private void readComplete(IAsyncResult result, Stream stream)
            {
                int bytesRead = stream.EndRead(result);
                var chunk     = _chunks[_chunks.Count - 1];

                chunk.Length += bytesRead;
                if (_dataEvent != null)
                {
                    var newBytes = new byte[bytesRead];
                    Array.Copy(chunk.Data, chunk.Length - bytesRead, newBytes, 0, bytesRead);
                    _dataEvent(newBytes);
                }
                if (_textEvent != null)
                {
                    var  newChars = new char[bytesRead + 1]; // can have at most one char buffered up in the decoder, plus bytesRead new chars
                    int  bytesUsed, charsUsed;
                    bool completed;
                    _decoder.Convert(chunk.Data, chunk.Length - bytesRead, bytesRead, newChars, 0, newChars.Length, false, out bytesUsed, out charsUsed, out completed);
                    Ut.Assert(completed); // it could still be halfway through a character; what this means is that newChars was large enough to accommodate everything
                    _textEvent(new string(newChars, 0, charsUsed));
                }
                if (bytesRead > 0) // continue reading
                {
                    ReadBegin(stream);
                }
                else
                {
                    Ended = true;
                    if (_textEvent != null)
                    {
                        var  newChars = new char[1];
                        int  bytesUsed, charsUsed;
                        bool completed;
                        _decoder.Convert(new byte[0], 0, 0, newChars, 0, newChars.Length, true, out bytesUsed, out charsUsed, out completed);
                        Ut.Assert(completed);
                        if (charsUsed > 0)
                        {
                            _textEvent(new string(newChars, 0, charsUsed));
                        }
                    }
                }
            }
Beispiel #4
0
        private void processExited(object sender, EventArgs e)
        {
            Ut.Assert(_process.HasExited);
            while (!_stdoutReader.Ended || !_stderrReader.Ended)
            {
                Thread.Sleep(20);
            }
            Ut.Assert(_stdoutReader.Ended);
            Ut.Assert(_stderrReader.Ended);
            if (_captureEntireStdout)
            {
                _entireStdout = _stdoutReader.GetEntireOutput();
            }
            if (_captureEntireStderr)
            {
                _entireStderr = _stderrReader.GetEntireOutput();
            }

            lock (_lock)
            {
                _pauseTimerDue = null;
                if (_pauseTimer != null)
                {
                    _pauseTimer.Dispose();
                }
            }
            _exitCode = _process.ExitCode;
            if (State != CommandRunnerState.Aborted)
            {
                State = CommandRunnerState.Exited;
            }

            _startInfo       = null;
            _process.Exited -= processExited;
            _process         = null;

            if (CommandEnded != null)
            {
                CommandEnded();
            }
            _ended.Set();
        }
Beispiel #5
0
        private static void wrap(StringBuilder text, ref int lineLength, int maxLineLength)
        {
            Ut.Assert(text.Length > 0);
            // This method MAY be called with a lineLength less than the max line length.
            // It MUST add a line wrap, ideally before the max line length, but if not possible then after the max length, possibly even at the very end of the text.

            // If the line already fits within max line length, just insert a newline at the very end and be done
            if (lineLength <= maxLineLength)
            {
                lineLength = 1;
                text.Append("\r\n ");
                return;
            }
            // First search back from the max line length position for a wrappable location
            int pos = text.Length - lineLength + maxLineLength; // "pos < text.Length" is guaranteed by the test above

            while (true)
            {
                if (pos < (text.Length - lineLength) || text[pos] == '\n') // exit if we've reached the start of the current line
                {
                    pos = -1;
                    break;
                }
                if (text[pos] == ' ')
                {
                    break;
                }
                pos--;
            }
            // If that worked, make sure it isn't all spaces until the start of the line
            if (pos >= 0)
            {
                int pos2 = pos;
                while (true)
                {
                    pos2--;
                    if (pos2 < (text.Length - lineLength) || text[pos2] == '\n')
                    {
                        pos = -1; // found nothing but spaces until the start of the line
                        break;
                    }
                    if (text[pos2] != ' ')
                    {
                        break; // found a non-space, so OK to wrap at "pos"
                    }
                }
            }
            // If that failed, seek forward
            if (pos < 0)
            {
                pos = text.Length - lineLength + maxLineLength + 1;
                while (true)
                {
                    if (pos >= text.Length)
                    {
                        break;
                    }
                    if (text[pos] == ' ')
                    {
                        break;
                    }
                    pos++;
                }
            }
            // Insert \r\n at "pos", which either points at the space that becomes the (mandatory) indent for the next line, or is at the very end of the line
            if (pos >= text.Length)
            {
                lineLength = 1;
                text.Append("\r\n ");
            }
            else
            {
                lineLength = text.Length - pos;
                text.Insert(pos, "\r\n");
            }
        }