summaryrefslogtreecommitdiff
path: root/apps/system/zmodem/zm_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/system/zmodem/zm_utils.c')
-rw-r--r--apps/system/zmodem/zm_utils.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/apps/system/zmodem/zm_utils.c b/apps/system/zmodem/zm_utils.c
new file mode 100644
index 000000000..f9fa2ae08
--- /dev/null
+++ b/apps/system/zmodem/zm_utils.c
@@ -0,0 +1,450 @@
+/****************************************************************************
+ * system/zmodem/zm_utils.c
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <crc32.h>
+
+#include "zm.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const uint8_t g_zeroes[4] = { 0, 0, 0, 0 };
+
+/****************************************************************************
+ * Public Function Protypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: zm_bytobe32
+ *
+ * Description:
+ * Convert a sequence of four bytes into a 32-bit value. The byte
+ * sequence is assumed to be big-endian.
+ *
+ ****************************************************************************/
+
+uint32_t zm_bytobe32(FAR const uint8_t *val8)
+{
+ return
+ (uint32_t)val8[3] << 24 |
+ (uint32_t)val8[2] << 16 |
+ (uint32_t)val8[1] << 8 |
+ (uint32_t)val8[0];
+}
+
+/****************************************************************************
+ * Name: zm_be32toby
+ *
+ * Description:
+ * Convert a 32-bit value in a sequence of four bytes in big-endian byte
+ * order.
+ *
+ ****************************************************************************/
+
+void zm_be32toby(uint32_t val32, FAR uint8_t *val8)
+{
+ val8[0] = (uint8_t)( val32 & 0xff);
+ val8[1] = (uint8_t)((val32 >> 8) & 0xff);
+ val8[2] = (uint8_t)((val32 >> 16) & 0xff);
+ val8[3] = (uint8_t)((val32 >> 24) & 0xff);
+}
+
+/****************************************************************************
+ * Name: zm_encnibble
+ *
+ * Description:
+ * Encode an 4-bit binary value to a single hex "digit".
+ *
+ ****************************************************************************/
+
+char zm_encnibble(uint8_t nibble)
+{
+ if (nibble < 10)
+ {
+ return nibble + '0';
+ }
+ else
+ {
+ return nibble + 'a' - 10;
+ }
+}
+
+/****************************************************************************
+ * Name: zm_encnibble
+ *
+ * Description:
+ * Decode an 4-bit binary value from a single hex "digit".
+ *
+ ****************************************************************************/
+
+uint8_t zm_decnibble(char hex)
+{
+ if (hex <= '9')
+ {
+ return hex - '0';
+ }
+ else if (hex <= 'F')
+ {
+ return hex - 'A' + 10;
+ }
+ else
+ {
+ return hex - 'a' + 10;
+ }
+}
+
+/****************************************************************************
+ * Name: zm_puthex8
+ *
+ * Description:
+ * Convert an 8-bit binary value to 2 hex "digits".
+ *
+ ****************************************************************************/
+
+FAR uint8_t *zm_puthex8(FAR uint8_t *ptr, uint8_t ch)
+{
+ *ptr++ = zm_encnibble((ch >> 4) & 0xf);
+ *ptr++ = zm_encnibble(ch & 0xf);
+ return ptr;
+}
+
+/****************************************************************************
+ * Name: zm_read
+ *
+ * Description:
+ * Read a buffer of data from a read-able stream.
+ *
+ ****************************************************************************/
+
+ssize_t zm_read(int fd, FAR uint8_t *buffer, size_t buflen)
+{
+ ssize_t nread;
+
+ /* Read reading as necessary until the requested buffer data is successfully
+ * read or until an end of file indication or irrecoverable error is
+ * encountered.
+ *
+ * This loop will only execute if the read is interrupted by a signal.
+ */
+
+ nread = 0;
+ do
+ {
+ /* Get the next gulp of data from the file. On success, read will return
+ * (1) nread > 0 and nread <= buflen, (2) nread == 0 on end of file, or
+ * (3) nread < 0 on a read error.
+ */
+
+ nread = read(fd, buffer, buflen);
+
+ /* Did some error occur? */
+
+ if (nread < 0)
+ {
+ int errorcode = errno;
+
+ /* EINTR is not an error... it simply means that this read was
+ * interrupted by an signal before it obtained in data.
+ */
+
+ if (errorcode != EINTR)
+ {
+ /* But anything else is bad and we will return the failure
+ * in those cases.
+ */
+
+ zmdbg("ERROR: read failed: %d\n", errorcode);
+ DEBUGASSERT(errorcode != 0);
+ return -errorcode;
+ }
+ }
+ }
+ while (nread < 0);
+
+ return (int)nread;
+}
+
+/****************************************************************************
+ * Name: zm_getc
+ *
+ * Description:
+ * Read a one byte of data from a read-able stream.
+ *
+ ****************************************************************************/
+
+int zm_getc(int fd)
+{
+ ssize_t nread;
+ uint8_t ch;
+
+ nread = zm_read(fd, &ch, 1);
+ if (nread <= 0)
+ {
+ return EOF;
+ }
+
+ return ch;
+}
+
+/****************************************************************************
+ * Name: zm_write
+ *
+ * Description:
+ * Write a buffer of data to a write-able stream.
+ *
+ ****************************************************************************/
+
+ssize_t zm_write(int fd, FAR const uint8_t *buffer, size_t buflen)
+{
+ ssize_t nwritten;
+ size_t total = 0;
+
+ /* Read reading as necessary until the requested buffer is filled or until
+ * an end of file indication or irrecoverable error is encountered.
+ */
+
+ while (total < buflen)
+ {
+ /* Get the next gulp of data from the file */
+
+ nwritten = write(fd, buffer, buflen);
+
+ if (nwritten < 0)
+ {
+ int errorcode = errno;
+
+ /* EINTR is not an error... it simply means that this read was
+ * interrupted by an signal before it obtained in data.
+ */
+
+ if (errorcode != EINTR)
+ {
+ zmdbg("ERROR: write failed: %d\n", errorcode);
+ DEBUGASSERT(errorcode != 0);
+ return -errorcode;
+ }
+ }
+ else
+ {
+ /* Updates counts and pointers for the next read */
+
+ total += nwritten;
+ buffer += nwritten;
+ buflen -= nwritten;
+ }
+ }
+
+ return (int)total;
+}
+
+/****************************************************************************
+ * Name: zm_remwrite
+ *
+ * Description:
+ * Write a buffer of data to the remote peer.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SYSTEM_ZMODEM_DUMPBUFFER
+ssize_t zm_remwrite(int fd, FAR const uint8_t *buffer, size_t buflen)
+{
+ zm_dumpbuffer("Sending", buffer, buflen);
+ return zm_write(fd, buffer, buflen);
+}
+#endif
+
+/****************************************************************************
+ * Name: zm_putc
+ *
+ * Description:
+ * Write a one byte of data to a write-able stream.
+ *
+ ****************************************************************************/
+
+#if 0 /* Not used */
+int zm_putc(int fd, uint8_t ch)
+{
+ ssize_t nwritten;
+
+ nwritten = zm_write(fd, &ch, 1);
+ if (nwritten <= 0)
+ {
+ return EOF
+ }
+
+ return ch;
+}
+#endif
+
+/****************************************************************************
+ * Name: zm_writefile
+ *
+ * Description:
+ * Write a buffer of data to file, performing newline conversions as
+ * necessary.
+ *
+ * NOTE: Not re-entrant. CR-LF sequences that span buffer boundaries are
+ * not guaranteed to to be handled correctly.
+ *
+ ****************************************************************************/
+
+int zm_writefile(int fd, FAR const uint8_t *buffer, size_t buflen, bool zcnl)
+{
+ int ret;
+
+ /* If zcnl set, convert newlines to Unix convention */
+
+ if (zcnl)
+ {
+ static bool newline = false;
+ FAR const uint8_t *start;
+ uint8_t ch;
+ int nbytes;
+
+ start = buffer;
+ nbytes = 0;
+ ret = OK;
+
+ /* Loop for each character in the buffer */
+
+ for (; buflen > 0 && ret == OK; buflen--)
+ {
+ /* Get the next character in the buffer */
+
+ ch = *buffer++;
+
+ /* Convert CR-LF, LF-CR, CR, and LF to LF */
+
+ if (ch == '\n' || ch == '\r')
+ {
+ if (nbytes > 0)
+ {
+ ret = zm_write(fd, start, nbytes);
+ start = buffer;
+ nbytes = 0;
+ }
+
+ if (ret == OK && !newline)
+ {
+ ret = zm_write(fd, (FAR uint8_t *)"\n", 1);
+ newline = true;
+ }
+ }
+ else
+ {
+ /* Increment the number of bytes we need to write beginning at
+ * start. We want to write as many contiguous bytes as possible
+ * for performance reasons.
+ */
+
+ nbytes++;
+ newline = false;
+ }
+ }
+
+ /* Write any trainling data that does not end with a newline */
+
+ if (ret == OK && nbytes > 0)
+ {
+ ret = zm_write(fd, start, nbytes);
+ }
+ }
+ else
+ {
+ /* We are not modifying newlines, let zm_write() do the whole job */
+
+ ret = zm_write(fd, buffer, buflen);
+ }
+
+ return ret;
+}
+
+/************************************************************************************************
+ * Name: zm_filecrc
+ *
+ * Description:
+ * Perform CRC32 calculation on a file.
+ *
+ * Assumptions:
+ * The allocated I/O buffer is available to buffer file data.
+ *
+ ************************************************************************************************/
+
+uint32_t zm_filecrc(FAR struct zm_state_s *pzm, FAR const char *filename)
+{
+ uint32_t crc;
+ ssize_t nread;
+ int fd;
+
+ /* Open the file for reading */
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ /* This should not happen */
+
+ zmdbg("ERROR: Failed to open %s: %d\n", filename, errno);
+ return 0;
+ }
+
+ /* Calculate the file CRC */
+
+ crc = 0xffffffff;
+ while ((nread = zm_read(fd, pzm->scratch, CONFIG_SYSTEM_ZMODEM_SNDBUFSIZE)) > 0)
+ {
+ crc = crc32part(pzm->rcvbuf, nread, crc);
+ }
+
+ /* Close the file and return the CRC */
+
+ close(fd);
+ return ~crc;
+}