Mercurial > octave
view libinterp/corefcn/hex2num.cc @ 30564:796f54d4ddbf stable
update Octave Project Developers copyright for the new year
In files that have the "Octave Project Developers" copyright notice,
update for 2021.
In all .txi and .texi files except gpl.txi and gpl.texi in the
doc/liboctave and doc/interpreter directories, change the copyright
to "Octave Project Developers", the same as used for other source
files. Update copyright notices for 2022 (not done since 2019). For
gpl.txi and gpl.texi, change the copyright notice to be "Free Software
Foundation, Inc." and leave the date at 2007 only because this file
only contains the text of the GPL, not anything created by the Octave
Project Developers.
Add Paul Thomas to contributors.in.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 28 Dec 2021 18:22:40 -0500 |
parents | 7d6709900da7 |
children | 83f9f8bda883 |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include "defun.h" #include "error.h" #include "errwarn.h" #include "mach-info.h" #include "ov.h" #include "ovl.h" #include "utils.h" OCTAVE_NAMESPACE_BEGIN static inline bool is_little_endian (bool is_float) { return ((is_float && (mach_info::native_float_format () == mach_info::flt_fmt_ieee_little_endian)) || mach_info::words_little_endian ()); } static uint8_t hex2nibble (unsigned char ch) { unsigned char val = 0; if (! isxdigit (ch)) error ("hex2num: invalid character '%c' found in string S", ch); if (ch >= 'a') val = static_cast<unsigned char> (ch - 'a' + 10); else if (ch >= 'A') val = static_cast<unsigned char> (ch - 'A' + 10); else val = static_cast<unsigned char> (ch - '0'); return val; } static void hex2num (const std::string& hex, void *num, std::size_t nbytes, bool swap_bytes) { unsigned char *cp = reinterpret_cast<unsigned char *> (num); const std::size_t nc = hex.length (); const std::size_t nchars = 2 * nbytes; if (nc > nchars) error ("hex2num: S must be no more than %zd characters", nchars); std::size_t j = 0; for (std::size_t i = 0; i < nbytes; i++) { std::size_t k = (swap_bytes ? nbytes - i - 1 : i); unsigned char ch1 = (j < nc) ? hex[j++] : '0'; unsigned char ch2 = (j < nc) ? hex[j++] : '0'; cp[k] = (hex2nibble (ch1) << 4) + hex2nibble (ch2); } } template <typename T> Array<T> hex2num (const Array<std::string>& val, bool swap_bytes) { octave_idx_type nel = val.numel (); Array<T> m (val.dims ()); std::size_t nbytes = sizeof (T); for (octave_idx_type i = 0; i < nel; i++) { T num; hex2num (val.xelem (i), &num, nbytes, swap_bytes); m(i) = num; } return m; } DEFUN (hex2num, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{n} =} hex2num (@var{s}) @deftypefnx {} {@var{n} =} hex2num (@var{s}, @var{class}) Typecast a hexadecimal character array or cell array of strings to an array of numbers. By default, the input array is interpreted as a hexadecimal number representing a double precision value. If fewer than 16 characters are given the strings are right padded with @qcode{'0'} characters. Given a string matrix, @code{hex2num} treats each row as a separate number. @example @group hex2num (["4005bf0a8b145769"; "4024000000000000"]) @result{} [2.7183; 10.000] @end group @end example The optional second argument @var{class} may be used to cause the input array to be interpreted as a different value type. Possible values are @multitable {Option} {Characters} @headitem Option @tab Characters @item @qcode{"int8"} @tab 2 @item @qcode{"uint8"} @tab 2 @item @qcode{"int16"} @tab 4 @item @qcode{"uint16"} @tab 4 @item @qcode{"int32"} @tab 8 @item @qcode{"uint32"} @tab 8 @item @qcode{"int64"} @tab 16 @item @qcode{"uint64"} @tab 16 @item @qcode{"char"} @tab 2 @item @qcode{"single"} @tab 8 @item @qcode{"double"} @tab 16 @end multitable For example: @example @group hex2num (["402df854"; "41200000"], "single") @result{} [2.7183; 10.000] @end group @end example @seealso{num2hex, hex2dec, dec2hex} @end deftypefn */) { octave_value retval; int nargin = args.length (); if (nargin < 1 || nargin > 2) print_usage (); std::string type = "double"; if (nargin == 2) type = args(1).xstring_value ("hex2num: CLASS must be a string"); Array<std::string> val = args(0).cellstr_value (); // We always use big-endian order for hex digits. bool is_float = type == "single" || type == "double"; bool swap_bytes = is_little_endian (is_float); if (type == "int8") retval = octave_value (hex2num<octave_int8> (val, swap_bytes)); else if (type == "uint8") retval = octave_value (hex2num<octave_uint8> (val, swap_bytes)); else if (type == "int16") retval = octave_value (hex2num<octave_int16> (val, swap_bytes)); else if (type == "uint16") retval = octave_value (hex2num<octave_uint16> (val, swap_bytes)); else if (type == "int32") retval = octave_value (hex2num<octave_int32> (val, swap_bytes)); else if (type == "uint32") retval = octave_value (hex2num<octave_uint32> (val, swap_bytes)); else if (type == "int64") retval = octave_value (hex2num<octave_int64> (val, swap_bytes)); else if (type == "uint64") retval = octave_value (hex2num<octave_uint64> (val, swap_bytes)); else if (type == "char") retval = octave_value (hex2num<char> (val, swap_bytes)); else if (type == "single") retval = octave_value (hex2num<float> (val, swap_bytes)); else if (type == "double") retval = octave_value (hex2num<double> (val, swap_bytes)); else error ("hex2num: unrecognized CLASS '%s'", type.c_str ()); return retval; } /* %!assert (hex2num (["c00";"bff";"000";"3ff";"400"]), [-2:2]') %!assert (hex2num (["c00";"bf8";"000";"3f8";"400"], "single"), single([-2:2])') %!assert (hex2num ("ff", "uint8"), intmax ("uint8")) %!assert (hex2num ("ffff", "uint16"), intmax ("uint16")) %!assert (hex2num ("ffffffff", "uint32"), intmax ("uint32")) %!assert (hex2num ("ffffffff", "uint32"), intmax ("uint32")) %!assert (hex2num ("ffffffffffffffff", "uint64"), intmax ("uint64")) */ static inline unsigned char nibble2hex (unsigned char ch) { if (ch >= 10) ch += 'a' - 10; else ch += '0'; return ch; } static inline void num2hex (const void *p, std::size_t n, char *hex, bool swap_bytes) { const unsigned char *cp = reinterpret_cast<const unsigned char *> (p); std::size_t k = 0; for (std::size_t i = 0; i < n; i++) { std::size_t j = (swap_bytes ? n - i - 1 : i); unsigned char ch = cp[j]; hex[k++] = nibble2hex ((ch >> 4) & 0xF); hex[k++] = nibble2hex (ch & 0xF); } } template <typename T> Cell num2hex (const Array<T>& v, bool swap_bytes) { const std::size_t nbytes = sizeof (T); const std::size_t nchars = 2 * nbytes; octave_idx_type nel = v.numel (); string_vector sv (nel); const T *pv = v.data (); for (octave_idx_type i = 0; i < nel; i++) { char hex[nchars]; num2hex (pv++, nbytes, hex, swap_bytes); sv[i] = std::string (hex, nchars); } return Cell (v.dims (), sv); } DEFUN (num2hex, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{s} =} num2hex (@var{n}) @deftypefnx {} {@var{s} =} num2hex (@var{n}, "cell") Convert a numeric array to an array of hexadecimal strings. For example: @example @group num2hex ([-1, 1, e, Inf]) @result{} "bff0000000000000 3ff0000000000000 4005bf0a8b145769 7ff0000000000000" @end group @end example If the argument @var{n} is a single precision number or vector, the returned string has a length of 8. For example: @example @group num2hex (single ([-1, 1, e, Inf])) @result{} "bf800000 3f800000 402df854 7f800000" @end group @end example With the optional second argument @qcode{"cell"}, return a cell array of strings instead of a character array. @seealso{hex2num, hex2dec, dec2hex} @end deftypefn */) { int nargin = args.length (); if (nargin < 1 || nargin > 2) print_usage (); bool as_cell = false; if (nargin == 2) { std::string opt = args(1).xstring_value ("num2hex: second argument must be a string"); if (opt == "cell") as_cell = true; else error ("num2hex: unrecognized option '%s'", opt.c_str ()); } octave_value val = args(0); if (val.iscomplex ()) error ("num2hex: N must be real"); Cell result; // We always use big-endian order for hex digits. bool is_float = val.is_single_type () || val.is_double_type (); bool swap_bytes = is_little_endian (is_float); if (val.is_int8_type ()) result = num2hex (val.int8_array_value (), swap_bytes); else if (val.is_int16_type ()) result = num2hex<octave_int16> (val.int16_array_value (), swap_bytes); else if (val.is_int32_type ()) result = num2hex<octave_int32> (val.int32_array_value (), swap_bytes); else if (val.is_int64_type ()) result = num2hex<octave_int64> (val.int64_array_value (), swap_bytes); else if (val.is_uint8_type ()) result = num2hex<octave_uint8> (val.uint8_array_value (), swap_bytes); else if (val.is_uint16_type ()) result = num2hex<octave_uint16> (val.uint16_array_value (), swap_bytes); else if (val.is_uint32_type ()) result = num2hex<octave_uint32> (val.uint32_array_value (), swap_bytes); else if (val.is_uint64_type ()) result = num2hex<octave_uint64> (val.uint64_array_value (), swap_bytes); else if (val.is_char_matrix ()) result = num2hex<char> (val.char_array_value (), swap_bytes); else if (val.is_single_type ()) result = num2hex<float> (val.float_vector_value (), swap_bytes); else if (val.is_double_type ()) result = num2hex<double> (val.vector_value (), swap_bytes); else err_wrong_type_arg ("num2hex", val); return (as_cell ? octave_value (result) : octave_value (result.string_vector_value ())); } /* %!assert (num2hex (-2:2), ["c000000000000000";"bff0000000000000";"0000000000000000";"3ff0000000000000";"4000000000000000"]) %!assert (num2hex (single (-2:2)), ["c0000000";"bf800000";"00000000";"3f800000";"40000000"]) %!assert (num2hex (intmax ("uint8")), "ff") %!assert (num2hex (intmax ("uint16")), "ffff") %!assert (num2hex (intmax ("uint32")), "ffffffff") %!assert (num2hex (intmax ("uint32")), "ffffffff") %!assert (num2hex (intmax ("uint64")), "ffffffffffffffff") %!assert (hex2num (num2hex (pi)), pi) %!assert (hex2num (num2hex (single (pi)), "single"), single (pi)) %!error num2hex () %!error num2hex (1,2) %!error num2hex (1,"foo") %!error num2hex (1,2,3) %!error num2hex (1j) */ OCTAVE_NAMESPACE_END