예제 #1
0
        private static byte[] GenerateDataSubpacketFrame(
            CRC32 crcCalculator, byte[] src, int offset, int chunkSize,
            ZDLESequence?forceZDLESequence = null)
        {
            // Slice data
            var dataSlice = src
                            .Skip(offset)
                            .Take(chunkSize)
                            .ToArray();

            var encodedDataSlice = ZDLEEncoder.EscapeControlCharacters(dataSlice);

            // If a ZDLESequence is forced we use that one.
            // Otherweise we take ZCRCQ and if the frame is the end frame, ZCRCE.
            var requiredSequence = forceZDLESequence.HasValue
                ? forceZDLESequence.Value
                : (offset + dataSlice.Length) < src.Length
                    ? ZDLESequence.ZCRCG
                    : ZDLESequence.ZCRCE;


            // Create data queue for the sliced data.
            var queue = new Queue <byte>(encodedDataSlice);

            // Create data for checksum
            var beforeCTC = dataSlice.Concat(new byte[] { (byte)requiredSequence }).ToArray();

            // Compute hash
            var crc = crcCalculator.ComputeHash(beforeCTC);

            // Add control characters
            queue.Enqueue((byte)ControlBytes.ZDLE);
            queue.Enqueue((byte)requiredSequence);

            var dataSubpacketFrame = queue?.ToArray();

            var encodedCRC = dataSubpacketFrame
                             .Concat(ZDLEEncoder.EscapeControlCharacters(crc))
                             .ToArray();

            return(encodedCRC);
        }
예제 #2
0
        /// <summary>
        /// The sender then sends a ZFILE header with ZMODEM Conversion, Management, and Transport options[3]
        /// followed by a ZCRCW data subpacket containing the file name, file length,
        /// modification date, and other information identical to that used by YMODEM Batch.
        /// </summary>
        /// <param name="fileInfo"></param>
        /// <param name="crcCalculator"></param>
        private bool SendZFILEHeaderCommand(string filename, int length, DateTimeOffset lastWriteTimeUtc, CRC32 crcCalculator)
        {
            var result = default(bool);

            var isExtended = true;

            var zFileHeader = Utils.Build32BitBinHeader(
                HeaderType.ZFILE,
                ZFILEConversionOption.ZCBIN,
                ZFILEManagementOption.ZMNEWL,
                ZFILETransportOption.None,
                ZFILEExtendedOptions.None,
                crcCalculator
                );

            var zFileHeaderQueue = new Queue <byte>();

            foreach (var c in zFileHeader)
            {
                zFileHeaderQueue.Enqueue((byte)c);
            }

            // Send ZFILE header first - No response
            SendCommand(zFileHeaderQueue.ToArray());

            var dataQueue = new Queue <byte>();

            foreach (char c in filename)
            {
                dataQueue.Enqueue((byte)c);
            }

            if (isExtended)
            {
                dataQueue.Enqueue(0);

                // File length as decimal string
                var fileLength = length.ToString();

                foreach (var c in fileLength)
                {
                    dataQueue.Enqueue((byte)c);
                }

                // Space
                dataQueue.Enqueue(0x20);

                var utcTime     = lastWriteTimeUtc.ToUnixTimeSeconds();
                var octalString = Convert.ToString(utcTime, 8);

                // Modification date
                foreach (var c in octalString)
                {
                    dataQueue.Enqueue((byte)c);
                }
            }
            else
            {
                // The file information is terminated by a null.
                // If only the pathname is sent, the pathname is terminated with two nulls.
                dataQueue.Enqueue(0);
                dataQueue.Enqueue(0);
            }

            byte[] data = dataQueue.Concat(new byte[] { (byte)ZDLESequence.ZCRCW }).ToArray();
            dataQueue.Enqueue((byte)ControlBytes.ZDLE);
            dataQueue.Enqueue((byte)ZDLESequence.ZCRCW);

            var crc = crcCalculator.ComputeHash(data);

            var encodedCRC = dataQueue
                             .Concat(ZDLEEncoder.EscapeControlCharacters(crc))
                             .ToArray();

            var response = SendCommand(encodedCRC, true, HeaderType.ZRPOS);

            // We expect ZRPOS
            if (response?.ZHeader == HeaderType.ZRPOS)
            {
                result = true;
            }

            /*
             * The receiver may respond with a ZSKIP header, which makes the sender
             * proceed to the next file (if any) in the batch.
             *
             * A ZRPOS header from the receiver initiates transmission of the file
             * data starting at the offset in the file specified in the ZRPOS header.
             * Normally the receiver specifies the data transfer to begin begin at
             * offset 0 in the file.
             */

            if (response?.ZHeader == HeaderType.ZSKIP ||
                response?.ZHeader == HeaderType.ZRPOS ||
                response?.ZHeader == HeaderType.ZCRC)
            {
                /*
                 * The receiver has a file with the same name and length, may
                 * respond with a ZCRC header with a byte count, which
                 * requires the sender to perform a 32 bit CRC on the
                 * specified number of bytes in the file and transmit the
                 * complement of the CRC in an answering ZCRC header.the crc is
                 * initialised to 0xfffffff; a byte count of 0 implies the entire
                 * file the receiver uses this information to determine whether to
                 * accept the file or skip it.  This sequence may be triggered
                 * by the ZMCRC Management Option.
                 */
            }

            return(result);
        }