diff options
Diffstat (limited to 'apps/system/zmodem/zm_utils.c')
-rw-r--r-- | apps/system/zmodem/zm_utils.c | 450 |
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; +} |